rubocop 1.73.1 → 1.74.0
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 +32 -4
- data/config/internal_affairs.yml +4 -0
- data/lib/rubocop/config_loader.rb +0 -1
- data/lib/rubocop/config_loader_resolver.rb +2 -1
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
- data/lib/rubocop/config_obsoletion.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +91 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +15 -70
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
- data/lib/rubocop/cop/lint/literal_as_condition.rb +4 -0
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +9 -3
- data/lib/rubocop/cop/lint/return_in_void_context.rb +4 -11
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +12 -1
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +2 -11
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +1 -1
- data/lib/rubocop/cop/mixin/range_help.rb +12 -0
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
- data/lib/rubocop/cop/style/class_and_module_children.rb +29 -7
- data/lib/rubocop/cop/style/commented_keyword.rb +9 -2
- data/lib/rubocop/cop/style/comparable_between.rb +75 -0
- data/lib/rubocop/cop/style/double_negation.rb +1 -1
- data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
- data/lib/rubocop/cop/style/exponential_notation.rb +2 -2
- data/lib/rubocop/cop/style/format_string_token.rb +38 -11
- data/lib/rubocop/cop/style/if_unless_modifier.rb +2 -2
- data/lib/rubocop/cop/style/inverse_methods.rb +8 -5
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +13 -7
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +3 -3
- data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
- data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +14 -4
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +3 -0
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +0 -6
- data/lib/rubocop/cop/utils/format_string.rb +5 -2
- data/lib/rubocop/directive_comment.rb +1 -1
- data/lib/rubocop/ext/regexp_node.rb +0 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +1 -0
- metadata +6 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 440bee0e28f294bab2eba4c11e9c681342917c69ad4c00e36eceb88743767c29
         | 
| 4 | 
            +
              data.tar.gz: 68e9e209a22e891a38b677f97344d2d10e9a8913dd999751472f301deed43b31
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 70db27a5b7a0e00696672a5b4fcd4e3bf35aa40c85ef65ccb630914ab110a5e5b657927aa1b1c8637be76b7041a90e2ad3c4ed188110266c048d0c4d6a4be0b4
         | 
| 7 | 
            +
              data.tar.gz: e5599d30a4f776d85d202acad2ac03c7e4568e64a1c4038cb87b8ee3372b2428882924a91ea49853c98cf0614280d002918363eef41fe0990dc8b1895d8e9776
         | 
    
        data/README.md
    CHANGED
    
    | @@ -52,7 +52,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi | |
| 52 52 | 
             
            in your `Gemfile`:
         | 
| 53 53 |  | 
| 54 54 | 
             
            ```rb
         | 
| 55 | 
            -
            gem 'rubocop', '~> 1. | 
| 55 | 
            +
            gem 'rubocop', '~> 1.74', require: false
         | 
| 56 56 | 
             
            ```
         | 
| 57 57 |  | 
| 58 58 | 
             
            See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
         | 
    
        data/config/default.yml
    CHANGED
    
    | @@ -1887,10 +1887,9 @@ Lint/EmptyConditionalBody: | |
| 1887 1887 | 
             
              Description: 'Checks for the presence of `if`, `elsif` and `unless` branches without a body.'
         | 
| 1888 1888 | 
             
              Enabled: true
         | 
| 1889 1889 | 
             
              AutoCorrect: contextual
         | 
| 1890 | 
            -
              SafeAutoCorrect: false
         | 
| 1891 1890 | 
             
              AllowComments: true
         | 
| 1892 1891 | 
             
              VersionAdded: '0.89'
         | 
| 1893 | 
            -
              VersionChanged: '1. | 
| 1892 | 
            +
              VersionChanged: '1.73'
         | 
| 1894 1893 |  | 
| 1895 1894 | 
             
            Lint/EmptyEnsure:
         | 
| 1896 1895 | 
             
              Description: 'Checks for empty ensure block.'
         | 
| @@ -3105,6 +3104,8 @@ Naming/VariableNumber: | |
| 3105 3104 | 
             
              CheckMethodNames: true
         | 
| 3106 3105 | 
             
              CheckSymbols: true
         | 
| 3107 3106 | 
             
              AllowedIdentifiers:
         | 
| 3107 | 
            +
                - TLS1_1       # OpenSSL::SSL::TLS1_1_VERSION
         | 
| 3108 | 
            +
                - TLS1_2       # OpenSSL::SSL::TLS1_2_VERSION
         | 
| 3108 3109 | 
             
                - capture3     # Open3.capture3
         | 
| 3109 3110 | 
             
                - iso8601      # Time#iso8601
         | 
| 3110 3111 | 
             
                - rfc1123_date # CGI.rfc1123_date
         | 
| @@ -3500,6 +3501,7 @@ Style/ClassAndModuleChildren: | |
| 3500 3501 | 
             
              SafeAutoCorrect: false
         | 
| 3501 3502 | 
             
              Enabled: true
         | 
| 3502 3503 | 
             
              VersionAdded: '0.19'
         | 
| 3504 | 
            +
              VersionChanged: '1.74'
         | 
| 3503 3505 | 
             
              #
         | 
| 3504 3506 | 
             
              # Basically there are two different styles:
         | 
| 3505 3507 | 
             
              #
         | 
| @@ -3515,7 +3517,21 @@ Style/ClassAndModuleChildren: | |
| 3515 3517 | 
             
              #
         | 
| 3516 3518 | 
             
              # The compact style is only forced, for classes or modules with one child.
         | 
| 3517 3519 | 
             
              EnforcedStyle: nested
         | 
| 3518 | 
            -
              SupportedStyles:
         | 
| 3520 | 
            +
              SupportedStyles: &supported_styles
         | 
| 3521 | 
            +
                - nested
         | 
| 3522 | 
            +
                - compact
         | 
| 3523 | 
            +
              # Configure classes separately, if desired. If not set, or set to `nil`,
         | 
| 3524 | 
            +
              # the `EnforcedStyle` value will be used.
         | 
| 3525 | 
            +
              EnforcedStyleForClasses: ~
         | 
| 3526 | 
            +
              SupportedStylesForClasses:
         | 
| 3527 | 
            +
                - ~
         | 
| 3528 | 
            +
                - nested
         | 
| 3529 | 
            +
                - compact
         | 
| 3530 | 
            +
              # Configure modules separately, if desired. If not set, or set to `nil`,
         | 
| 3531 | 
            +
              # the `EnforcedStyle` value will be used.
         | 
| 3532 | 
            +
              EnforcedStyleForModules: ~
         | 
| 3533 | 
            +
              SupportedStylesForModules:
         | 
| 3534 | 
            +
                - ~
         | 
| 3519 3535 | 
             
                - nested
         | 
| 3520 3536 | 
             
                - compact
         | 
| 3521 3537 |  | 
| @@ -3668,6 +3684,12 @@ Style/CommentedKeyword: | |
| 3668 3684 | 
             
              VersionAdded: '0.51'
         | 
| 3669 3685 | 
             
              VersionChanged: '1.19'
         | 
| 3670 3686 |  | 
| 3687 | 
            +
            Style/ComparableBetween:
         | 
| 3688 | 
            +
              Description: 'Enforces the use of `Comparable#between?` instead of logical comparison.'
         | 
| 3689 | 
            +
              Enabled: pending
         | 
| 3690 | 
            +
              VersionAdded: '1.74'
         | 
| 3691 | 
            +
              StyleGuide: '#ranges-or-between'
         | 
| 3692 | 
            +
             | 
| 3671 3693 | 
             
            Style/ComparableClamp:
         | 
| 3672 3694 | 
             
              Description: 'Enforces the use of `Comparable#clamp` instead of comparison by minimum and maximum.'
         | 
| 3673 3695 | 
             
              Enabled: pending
         | 
| @@ -4070,8 +4092,14 @@ Style/FormatStringToken: | |
| 4070 4092 | 
             
              # style token in a format string to be allowed when enforced style is not
         | 
| 4071 4093 | 
             
              # `unannotated`.
         | 
| 4072 4094 | 
             
              MaxUnannotatedPlaceholdersAllowed: 1
         | 
| 4095 | 
            +
              # The mode the cop operates in. Two values are allowed:
         | 
| 4096 | 
            +
              # * aggressive (default): all strings are considered
         | 
| 4097 | 
            +
              # * conservative:
         | 
| 4098 | 
            +
              #     only register offenses for strings given to `printf`, `sprintf`,
         | 
| 4099 | 
            +
              #     format` and `%` methods. Other strings are not considered.
         | 
| 4100 | 
            +
              Mode: aggressive
         | 
| 4073 4101 | 
             
              VersionAdded: '0.49'
         | 
| 4074 | 
            -
              VersionChanged: '1. | 
| 4102 | 
            +
              VersionChanged: '1.74'
         | 
| 4075 4103 | 
             
              AllowedMethods: []
         | 
| 4076 4104 | 
             
              AllowedPatterns: []
         | 
| 4077 4105 |  | 
    
        data/config/internal_affairs.yml
    CHANGED
    
    
| @@ -63,7 +63,6 @@ module RuboCop | |
| 63 63 | 
             
                    loaded_features = resolver.resolve_requires(path, hash)
         | 
| 64 64 | 
             
                    add_loaded_features(loaded_features)
         | 
| 65 65 |  | 
| 66 | 
            -
                    resolver.override_department_setting_for_cops({}, hash)
         | 
| 67 66 | 
             
                    resolver.resolve_inheritance_from_gems(hash)
         | 
| 68 67 | 
             
                    resolver.resolve_inheritance(path, hash, file, debug?)
         | 
| 69 68 | 
             
                    hash.delete('inherit_from')
         | 
| @@ -9,7 +9,8 @@ module RuboCop | |
| 9 9 | 
             
              # @api private
         | 
| 10 10 | 
             
              class ConfigLoaderResolver # rubocop:disable Metrics/ClassLength
         | 
| 11 11 | 
             
                def resolve_plugins(rubocop_config, plugins)
         | 
| 12 | 
            -
                   | 
| 12 | 
            +
                  plugins = Array(plugins) - ConfigLoader.loaded_plugins.map { |plugin| plugin.about.name }
         | 
| 13 | 
            +
                  return if plugins.empty?
         | 
| 13 14 |  | 
| 14 15 | 
             
                  Plugin.integrate_plugins(rubocop_config, plugins)
         | 
| 15 16 | 
             
                end
         | 
| @@ -15,7 +15,7 @@ module RuboCop | |
| 15 15 | 
             
                  end
         | 
| 16 16 |  | 
| 17 17 | 
             
                  def violated?
         | 
| 18 | 
            -
                    return false if  | 
| 18 | 
            +
                    return false if plugin_loaded?
         | 
| 19 19 |  | 
| 20 20 | 
             
                    affected_cops.any?
         | 
| 21 21 | 
             
                  end
         | 
| @@ -38,8 +38,9 @@ module RuboCop | |
| 38 38 | 
             
                    end
         | 
| 39 39 | 
             
                  end
         | 
| 40 40 |  | 
| 41 | 
            -
                  def  | 
| 42 | 
            -
                     | 
| 41 | 
            +
                  def plugin_loaded?
         | 
| 42 | 
            +
                    # Plugins loaded via `require` are included in `loaded_features`.
         | 
| 43 | 
            +
                    config.loaded_plugins.include?(gem) || config.loaded_features.include?(gem)
         | 
| 43 44 | 
             
                  end
         | 
| 44 45 | 
             
                end
         | 
| 45 46 | 
             
              end
         | 
| @@ -50,7 +50,7 @@ module RuboCop | |
| 50 50 | 
             
                # Default rules for obsoletions are in config/obsoletion.yml
         | 
| 51 51 | 
             
                # Additional rules files can be added with `RuboCop::ConfigObsoletion.files << filename`
         | 
| 52 52 | 
             
                def load_rules # rubocop:disable Metrics/AbcSize
         | 
| 53 | 
            -
                  rules = LOAD_RULES_CACHE[self.class.files] ||=
         | 
| 53 | 
            +
                  rules = LOAD_RULES_CACHE[self.class.files.hash] ||=
         | 
| 54 54 | 
             
                    self.class.files.each_with_object({}) do |filename, hash|
         | 
| 55 55 | 
             
                      hash.merge!(YAML.safe_load(File.read(filename)) || {}) do |_key, first, second|
         | 
| 56 56 | 
             
                        case first
         | 
| @@ -50,10 +50,12 @@ module RuboCop | |
| 50 50 | 
             
                    }.freeze
         | 
| 51 51 |  | 
| 52 52 | 
             
                    EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING = {
         | 
| 53 | 
            -
                      /\A(auto[- ]?)? | 
| 53 | 
            +
                      /\A(auto[- ]?)?corrects?/ => 'does not correct',
         | 
| 54 | 
            +
                      /\band (auto[- ]?)?corrects/ => 'but does not correct'
         | 
| 54 55 | 
             
                    }.freeze
         | 
| 55 56 |  | 
| 56 57 | 
             
                    EXPECT_CORRECTION_DESCRIPTION_MAPPING = {
         | 
| 58 | 
            +
                      /\bbut (does not|doesn't) (auto[- ]?)?correct/ => 'and autocorrects',
         | 
| 57 59 | 
             
                      /\b(does not|doesn't) (auto[- ]?)?correct/ => 'autocorrects'
         | 
| 58 60 | 
             
                    }.freeze
         | 
| 59 61 |  | 
| @@ -0,0 +1,91 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module RuboCop
         | 
| 4 | 
            +
              module Cop
         | 
| 5 | 
            +
                module InternalAffairs
         | 
| 6 | 
            +
                  # Checks that node types are checked against their group when all types of a
         | 
| 7 | 
            +
                  # group are checked.
         | 
| 8 | 
            +
                  #
         | 
| 9 | 
            +
                  # @example
         | 
| 10 | 
            +
                  #   # bad
         | 
| 11 | 
            +
                  #   node.type?(:irange, :erange)
         | 
| 12 | 
            +
                  #
         | 
| 13 | 
            +
                  #   # good
         | 
| 14 | 
            +
                  #   node.range_type?
         | 
| 15 | 
            +
                  #
         | 
| 16 | 
            +
                  #   # bad
         | 
| 17 | 
            +
                  #   node.type?(:irange, :erange, :send, :csend)
         | 
| 18 | 
            +
                  #
         | 
| 19 | 
            +
                  #   # good
         | 
| 20 | 
            +
                  #   node.type?(:range, :call)
         | 
| 21 | 
            +
                  #
         | 
| 22 | 
            +
                  class NodeTypeGroup < Base
         | 
| 23 | 
            +
                    extend AutoCorrector
         | 
| 24 | 
            +
                    include RangeHelp
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    MSG = 'Use `:%<group>s` instead of individually listing group types.'
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    RESTRICT_ON_SEND = %i[type? each_ancestor each_child_node each_descendant each_node].freeze
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    def on_send(node)
         | 
| 31 | 
            +
                      return unless node.receiver
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                      symbol_args = node.arguments.select(&:sym_type?)
         | 
| 34 | 
            +
                      return if symbol_args.none?
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                      NodePatternGroups::NODE_GROUPS.each do |group_name, group_types|
         | 
| 37 | 
            +
                        next unless group_satisfied?(group_types, symbol_args)
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                        offense_range = arguments_range(node)
         | 
| 40 | 
            +
                        add_offense(offense_range, message: format(MSG, group: group_name)) do |corrector|
         | 
| 41 | 
            +
                          autocorrect(corrector, node, symbol_args, group_name, group_types)
         | 
| 42 | 
            +
                        end
         | 
| 43 | 
            +
                      end
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
                    alias on_csend on_send
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    private
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    def arguments_range(node)
         | 
| 50 | 
            +
                      range_between(
         | 
| 51 | 
            +
                        node.first_argument.source_range.begin_pos,
         | 
| 52 | 
            +
                        node.last_argument.source_range.end_pos
         | 
| 53 | 
            +
                      )
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    def group_satisfied?(group_types, symbol_args)
         | 
| 57 | 
            +
                      group_types.all? { |type| symbol_args.any? { |arg| arg.value == type } }
         | 
| 58 | 
            +
                    end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                    def autocorrect(corrector, node, symbol_args, group_name, group_types)
         | 
| 61 | 
            +
                      if node.method?(:type?) && node.arguments.count == group_types.count
         | 
| 62 | 
            +
                        autocorrect_to_explicit_predicate(corrector, node, group_name)
         | 
| 63 | 
            +
                      else
         | 
| 64 | 
            +
                        autocorrect_keep_method(corrector, symbol_args, group_name, group_types)
         | 
| 65 | 
            +
                      end
         | 
| 66 | 
            +
                    end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                    def autocorrect_to_explicit_predicate(corrector, node, group_name)
         | 
| 69 | 
            +
                      corrector.replace(node.selector, "#{group_name}_type?")
         | 
| 70 | 
            +
                      corrector.remove(arguments_range(node))
         | 
| 71 | 
            +
                    end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    def autocorrect_keep_method(corrector, symbol_args, group_name, group_types)
         | 
| 74 | 
            +
                      first_replaced = false
         | 
| 75 | 
            +
                      symbol_args.each do |arg|
         | 
| 76 | 
            +
                        next unless group_types.include?(arg.value)
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                        if first_replaced
         | 
| 79 | 
            +
                          range = range_with_surrounding_space(arg.source_range)
         | 
| 80 | 
            +
                          range = range_with_surrounding_comma(range, :left)
         | 
| 81 | 
            +
                          corrector.remove(range)
         | 
| 82 | 
            +
                        else
         | 
| 83 | 
            +
                          first_replaced = true
         | 
| 84 | 
            +
                          corrector.replace(arg, ":#{group_name}")
         | 
| 85 | 
            +
                        end
         | 
| 86 | 
            +
                      end
         | 
| 87 | 
            +
                    end
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
            end
         | 
| @@ -17,6 +17,7 @@ require_relative 'internal_affairs/node_destructuring' | |
| 17 17 | 
             
            require_relative 'internal_affairs/node_first_or_last_argument'
         | 
| 18 18 | 
             
            require_relative 'internal_affairs/node_matcher_directive'
         | 
| 19 19 | 
             
            require_relative 'internal_affairs/node_pattern_groups'
         | 
| 20 | 
            +
            require_relative 'internal_affairs/node_type_group'
         | 
| 20 21 | 
             
            require_relative 'internal_affairs/node_type_multiple_predicates'
         | 
| 21 22 | 
             
            require_relative 'internal_affairs/node_type_predicate'
         | 
| 22 23 | 
             
            require_relative 'internal_affairs/numblock_handler'
         | 
| @@ -7,11 +7,6 @@ module RuboCop | |
| 7 7 | 
             
                  #
         | 
| 8 8 | 
             
                  # NOTE: empty `else` branches are handled by `Style/EmptyElse`.
         | 
| 9 9 | 
             
                  #
         | 
| 10 | 
            -
                  # @safety
         | 
| 11 | 
            -
                  #   Autocorrection for this cop is not safe. The conditions for empty branches that
         | 
| 12 | 
            -
                  #   the autocorrection removes may have side effects, or the logic in subsequent
         | 
| 13 | 
            -
                  #   branches may change due to the removal of a previous condition.
         | 
| 14 | 
            -
                  #
         | 
| 15 10 | 
             
                  # @example
         | 
| 16 11 | 
             
                  #   # bad
         | 
| 17 12 | 
             
                  #   if condition
         | 
| @@ -41,6 +36,13 @@ module RuboCop | |
| 41 36 | 
             
                  #   if condition
         | 
| 42 37 | 
             
                  #     do_something
         | 
| 43 38 | 
             
                  #   elsif other_condition
         | 
| 39 | 
            +
                  #     nil
         | 
| 40 | 
            +
                  #   end
         | 
| 41 | 
            +
                  #
         | 
| 42 | 
            +
                  #   # good
         | 
| 43 | 
            +
                  #   if condition
         | 
| 44 | 
            +
                  #     do_something
         | 
| 45 | 
            +
                  #   elsif other_condition
         | 
| 44 46 | 
             
                  #     do_something_else
         | 
| 45 47 | 
             
                  #   end
         | 
| 46 48 | 
             
                  #
         | 
| @@ -63,7 +65,6 @@ module RuboCop | |
| 63 65 | 
             
                  class EmptyConditionalBody < Base
         | 
| 64 66 | 
             
                    extend AutoCorrector
         | 
| 65 67 | 
             
                    include CommentsHelp
         | 
| 66 | 
            -
                    include RangeHelp
         | 
| 67 68 |  | 
| 68 69 | 
             
                    MSG = 'Avoid `%<keyword>s` branches without a body.'
         | 
| 69 70 |  | 
| @@ -74,21 +75,14 @@ module RuboCop | |
| 74 75 | 
             
                      range = offense_range(node)
         | 
| 75 76 |  | 
| 76 77 | 
             
                      add_offense(range, message: format(MSG, keyword: node.keyword)) do |corrector|
         | 
| 77 | 
            -
                         | 
| 78 | 
            +
                        next unless can_simplify_conditional?(node)
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                        flip_orphaned_else(corrector, node)
         | 
| 78 81 | 
             
                      end
         | 
| 79 82 | 
             
                    end
         | 
| 80 83 |  | 
| 81 84 | 
             
                    private
         | 
| 82 85 |  | 
| 83 | 
            -
                    def do_autocorrect?(node)
         | 
| 84 | 
            -
                      # if condition; end.do_something
         | 
| 85 | 
            -
                      return false if (parent = node.parent)&.call_type?
         | 
| 86 | 
            -
                      # x = if condition; end
         | 
| 87 | 
            -
                      return false if (parent&.assignment? || parent&.operator_keyword?) && node.children.one?
         | 
| 88 | 
            -
             | 
| 89 | 
            -
                      true
         | 
| 90 | 
            -
                    end
         | 
| 91 | 
            -
             | 
| 92 86 | 
             
                    def offense_range(node)
         | 
| 93 87 | 
             
                      if node.loc.else
         | 
| 94 88 | 
             
                        node.source_range.begin.join(node.loc.else.begin)
         | 
| @@ -97,53 +91,23 @@ module RuboCop | |
| 97 91 | 
             
                      end
         | 
| 98 92 | 
             
                    end
         | 
| 99 93 |  | 
| 100 | 
            -
                    def  | 
| 101 | 
            -
                       | 
| 102 | 
            -
                      remove_empty_branch(corrector, node)
         | 
| 103 | 
            -
                      correct_other_branches(corrector, node)
         | 
| 104 | 
            -
                    end
         | 
| 105 | 
            -
             | 
| 106 | 
            -
                    def remove_comments(corrector, node)
         | 
| 107 | 
            -
                      comments_in_range(node).each do |comment|
         | 
| 108 | 
            -
                        range = range_by_whole_lines(comment.source_range, include_final_newline: true)
         | 
| 109 | 
            -
                        corrector.remove(range)
         | 
| 110 | 
            -
                      end
         | 
| 94 | 
            +
                    def can_simplify_conditional?(node)
         | 
| 95 | 
            +
                      node.else_branch && node.loc.else.source == 'else'
         | 
| 111 96 | 
             
                    end
         | 
| 112 97 |  | 
| 113 | 
            -
                    # rubocop:disable Metrics/AbcSize
         | 
| 114 98 | 
             
                    def remove_empty_branch(corrector, node)
         | 
| 115 99 | 
             
                      range = if empty_if_branch?(node) && else_branch?(node)
         | 
| 116 100 | 
             
                                branch_range(node)
         | 
| 117 | 
            -
                              elsif same_line?(node, else_kw_loc = node.loc.else)
         | 
| 118 | 
            -
                                node.source_range.begin.join(else_kw_loc.begin)
         | 
| 119 | 
            -
                              elsif node.parent&.loc.respond_to?(:end) &&
         | 
| 120 | 
            -
                                    same_line?(node, end_loc = node.parent.loc.end)
         | 
| 121 | 
            -
                                node.source_range.begin.join(end_loc.begin)
         | 
| 122 101 | 
             
                              else
         | 
| 123 102 | 
             
                                deletion_range(branch_range(node))
         | 
| 124 103 | 
             
                              end
         | 
| 125 104 |  | 
| 126 105 | 
             
                      corrector.remove(range)
         | 
| 127 106 | 
             
                    end
         | 
| 128 | 
            -
                    # rubocop:enable Metrics/AbcSize
         | 
| 129 107 |  | 
| 130 | 
            -
                    def  | 
| 131 | 
            -
                       | 
| 132 | 
            -
             | 
| 133 | 
            -
                      if node.else_branch&.if_type? && !node.else_branch.modifier_form?
         | 
| 134 | 
            -
                        # Replace an orphaned `elsif` with `if`
         | 
| 135 | 
            -
                        corrector.replace(node.else_branch.loc.keyword, 'if')
         | 
| 136 | 
            -
                      else
         | 
| 137 | 
            -
                        # Flip orphaned `else`
         | 
| 138 | 
            -
                        corrector.replace(node.loc.else, "#{node.inverse_keyword} #{node.condition.source}")
         | 
| 139 | 
            -
                      end
         | 
| 140 | 
            -
                    end
         | 
| 141 | 
            -
             | 
| 142 | 
            -
                    def require_other_branches_correction?(node)
         | 
| 143 | 
            -
                      return false unless node.if_type? && node.else?
         | 
| 144 | 
            -
                      return false if !empty_if_branch?(node) && node.elsif?
         | 
| 145 | 
            -
             | 
| 146 | 
            -
                      !empty_elsif_branch?(node)
         | 
| 108 | 
            +
                    def flip_orphaned_else(corrector, node)
         | 
| 109 | 
            +
                      corrector.replace(node.loc.else, "#{node.inverse_keyword} #{node.condition.source}")
         | 
| 110 | 
            +
                      remove_empty_branch(corrector, node)
         | 
| 147 111 | 
             
                    end
         | 
| 148 112 |  | 
| 149 113 | 
             
                    def empty_if_branch?(node)
         | 
| @@ -154,36 +118,17 @@ module RuboCop | |
| 154 118 | 
             
                      if_branch.if_type? && !if_branch.body
         | 
| 155 119 | 
             
                    end
         | 
| 156 120 |  | 
| 157 | 
            -
                    def empty_elsif_branch?(node)
         | 
| 158 | 
            -
                      return false unless (else_branch = node.else_branch)
         | 
| 159 | 
            -
             | 
| 160 | 
            -
                      else_branch.if_type? && !else_branch.body
         | 
| 161 | 
            -
                    end
         | 
| 162 | 
            -
             | 
| 163 121 | 
             
                    def else_branch?(node)
         | 
| 164 122 | 
             
                      node.else_branch && !node.else_branch.if_type?
         | 
| 165 123 | 
             
                    end
         | 
| 166 124 |  | 
| 167 | 
            -
                    # rubocop:disable Metrics/AbcSize
         | 
| 168 125 | 
             
                    def branch_range(node)
         | 
| 169 126 | 
             
                      if empty_if_branch?(node) && else_branch?(node)
         | 
| 170 127 | 
             
                        node.source_range.with(end_pos: node.loc.else.begin_pos)
         | 
| 171 128 | 
             
                      elsif node.loc.else
         | 
| 172 129 | 
             
                        node.source_range.with(end_pos: node.condition.source_range.end_pos)
         | 
| 173 | 
            -
                      elsif all_branches_body_missing?(node)
         | 
| 174 | 
            -
                        if_node = node.ancestors.detect(&:if?)
         | 
| 175 | 
            -
                        node.source_range.join(if_node.loc.end.end)
         | 
| 176 | 
            -
                      else
         | 
| 177 | 
            -
                        node.source_range
         | 
| 178 130 | 
             
                      end
         | 
| 179 131 | 
             
                    end
         | 
| 180 | 
            -
                    # rubocop:enable Metrics/AbcSize
         | 
| 181 | 
            -
             | 
| 182 | 
            -
                    def all_branches_body_missing?(node)
         | 
| 183 | 
            -
                      return false unless node.parent&.if_type?
         | 
| 184 | 
            -
             | 
| 185 | 
            -
                      node.parent.branches.compact.empty?
         | 
| 186 | 
            -
                    end
         | 
| 187 132 |  | 
| 188 133 | 
             
                    def deletion_range(range)
         | 
| 189 134 | 
             
                      # Collect a range between the start of the `if` node and the next relevant node,
         | 
| @@ -156,12 +156,6 @@ module RuboCop | |
| 156 156 |  | 
| 157 157 | 
             
                      overridden_kwargs
         | 
| 158 158 | 
             
                    end
         | 
| 159 | 
            -
             | 
| 160 | 
            -
                    def arguments_range(node)
         | 
| 161 | 
            -
                      arguments = node.arguments
         | 
| 162 | 
            -
             | 
| 163 | 
            -
                      range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos)
         | 
| 164 | 
            -
                    end
         | 
| 165 159 | 
             
                  end
         | 
| 166 160 | 
             
                end
         | 
| 167 161 | 
             
              end
         | 
| @@ -46,6 +46,10 @@ module RuboCop | |
| 46 46 | 
             
                      return unless node.lhs.truthy_literal?
         | 
| 47 47 |  | 
| 48 48 | 
             
                      add_offense(node.lhs) do |corrector|
         | 
| 49 | 
            +
                        # Don't autocorrect `'foo' && return` because having `return` as
         | 
| 50 | 
            +
                        # the leftmost node can lead to a void value expression syntax error.
         | 
| 51 | 
            +
                        next if node.rhs.type?(:return, :break, :next)
         | 
| 52 | 
            +
             | 
| 49 53 | 
             
                        corrector.replace(node, node.rhs.source)
         | 
| 50 54 | 
             
                      end
         | 
| 51 55 | 
             
                    end
         | 
| @@ -46,7 +46,7 @@ module RuboCop | |
| 46 46 | 
             
                    def on_return(return_node)
         | 
| 47 47 | 
             
                      return if return_value?(return_node)
         | 
| 48 48 |  | 
| 49 | 
            -
                      return_node.each_ancestor(: | 
| 49 | 
            +
                      return_node.each_ancestor(:any_block, :def, :defs) do |node|
         | 
| 50 50 | 
             
                        break if scoped_node?(node)
         | 
| 51 51 |  | 
| 52 52 | 
             
                        # if a proc is passed to `Module#define_method` or
         | 
| @@ -54,7 +54,7 @@ module RuboCop | |
| 54 54 | 
             
                        # non-local exit error
         | 
| 55 55 | 
             
                        break if define_method?(node.send_node)
         | 
| 56 56 |  | 
| 57 | 
            -
                        next  | 
| 57 | 
            +
                        next if node.argument_list.empty?
         | 
| 58 58 |  | 
| 59 59 | 
             
                        if chained_send?(node.send_node)
         | 
| 60 60 | 
             
                          add_offense(return_node.loc.keyword)
         | 
| @@ -3,13 +3,13 @@ | |
| 3 3 | 
             
            module RuboCop
         | 
| 4 4 | 
             
              module Cop
         | 
| 5 5 | 
             
                module Lint
         | 
| 6 | 
            -
                  # Checks for redundant uses of `to_s`, `to_sym`, `to_i`, `to_f`, `to_r`, `to_c`,
         | 
| 6 | 
            +
                  # Checks for redundant uses of `to_s`, `to_sym`, `to_i`, `to_f`, `to_d`, `to_r`, `to_c`,
         | 
| 7 7 | 
             
                  # `to_a`, `to_h`, and `to_set`.
         | 
| 8 8 | 
             
                  #
         | 
| 9 9 | 
             
                  # When one of these methods is called on an object of the same type, that object
         | 
| 10 10 | 
             
                  # is returned, making the call unnecessary. The cop detects conversion methods called
         | 
| 11 11 | 
             
                  # on object literals, class constructors, class `[]` methods, and the `Kernel` methods
         | 
| 12 | 
            -
                  # `String()`, `Integer()`, `Float()`, `Rational()`, `Complex() | 
| 12 | 
            +
                  # `String()`, `Integer()`, `Float()`, BigDecimal(), `Rational()`, `Complex()`, and `Array()`.
         | 
| 13 13 | 
             
                  #
         | 
| 14 14 | 
             
                  # Specifically, these cases are detected for each conversion method:
         | 
| 15 15 | 
             
                  #
         | 
| @@ -98,6 +98,7 @@ module RuboCop | |
| 98 98 | 
             
                      to_s: 'string_constructor?',
         | 
| 99 99 | 
             
                      to_i: 'integer_constructor?',
         | 
| 100 100 | 
             
                      to_f: 'float_constructor?',
         | 
| 101 | 
            +
                      to_d: 'bigdecimal_constructor?',
         | 
| 101 102 | 
             
                      to_r: 'rational_constructor?',
         | 
| 102 103 | 
             
                      to_c: 'complex_constructor?',
         | 
| 103 104 | 
             
                      to_a: 'array_constructor?',
         | 
| @@ -110,7 +111,7 @@ module RuboCop | |
| 110 111 | 
             
                    TYPED_METHODS = { to_s: %i[inspect] }.freeze
         | 
| 111 112 |  | 
| 112 113 | 
             
                    CONVERSION_METHODS = Set[*LITERAL_NODE_TYPES.keys].freeze
         | 
| 113 | 
            -
                    RESTRICT_ON_SEND = CONVERSION_METHODS
         | 
| 114 | 
            +
                    RESTRICT_ON_SEND = CONVERSION_METHODS + [:to_d]
         | 
| 114 115 |  | 
| 115 116 | 
             
                    private_constant :LITERAL_NODE_TYPES, :CONSTRUCTOR_MAPPING
         | 
| 116 117 |  | 
| @@ -137,6 +138,11 @@ module RuboCop | |
| 137 138 | 
             
                      #type_constructor?(:Float)
         | 
| 138 139 | 
             
                    PATTERN
         | 
| 139 140 |  | 
| 141 | 
            +
                    # @!method bigdecimal_constructor?(node)
         | 
| 142 | 
            +
                    def_node_matcher :bigdecimal_constructor?, <<~PATTERN
         | 
| 143 | 
            +
                      #type_constructor?(:BigDecimal)
         | 
| 144 | 
            +
                    PATTERN
         | 
| 145 | 
            +
             | 
| 140 146 | 
             
                    # @!method rational_constructor?(node)
         | 
| 141 147 | 
             
                    def_node_matcher :rational_constructor?, <<~PATTERN
         | 
| 142 148 | 
             
                      #type_constructor?(:Rational)
         | 
| @@ -35,22 +35,15 @@ module RuboCop | |
| 35 35 | 
             
                    def on_return(return_node)
         | 
| 36 36 | 
             
                      return unless return_node.descendants.any?
         | 
| 37 37 |  | 
| 38 | 
            -
                       | 
| 39 | 
            -
             | 
| 40 | 
            -
                      return  | 
| 41 | 
            -
                      return unless context_node&.void_context?
         | 
| 38 | 
            +
                      def_node = return_node.each_ancestor(:def).first
         | 
| 39 | 
            +
                      return unless def_node&.void_context?
         | 
| 40 | 
            +
                      return if return_node.each_ancestor(:any_block).any?(&:lambda?)
         | 
| 42 41 |  | 
| 43 42 | 
             
                      add_offense(
         | 
| 44 43 | 
             
                        return_node.loc.keyword,
         | 
| 45 | 
            -
                        message: format(message, method:  | 
| 44 | 
            +
                        message: format(message, method: def_node.method_name)
         | 
| 46 45 | 
             
                      )
         | 
| 47 46 | 
             
                    end
         | 
| 48 | 
            -
             | 
| 49 | 
            -
                    private
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                    def non_void_context(return_node)
         | 
| 52 | 
            -
                      return_node.each_ancestor(:block, :def, :defs).first
         | 
| 53 | 
            -
                    end
         | 
| 54 47 | 
             
                  end
         | 
| 55 48 | 
             
                end
         | 
| 56 49 | 
             
              end
         | 
| @@ -51,7 +51,18 @@ module RuboCop | |
| 51 51 |  | 
| 52 52 | 
             
                    # @!method hash_initialized_with_mutable_shared_object?(node)
         | 
| 53 53 | 
             
                    def_node_matcher :hash_initialized_with_mutable_shared_object?, <<~PATTERN
         | 
| 54 | 
            -
                       | 
| 54 | 
            +
                      {
         | 
| 55 | 
            +
                        (send (const {nil? cbase} :Hash) :new [
         | 
| 56 | 
            +
                          {array hash (send (const {nil? cbase} {:Array :Hash}) :new)}
         | 
| 57 | 
            +
                          !#capacity_keyword_argument?
         | 
| 58 | 
            +
                        ])
         | 
| 59 | 
            +
                        (send (const {nil? cbase} :Hash) :new hash #capacity_keyword_argument?)
         | 
| 60 | 
            +
                      }
         | 
| 61 | 
            +
                    PATTERN
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    # @!method capacity_keyword_argument?(node)
         | 
| 64 | 
            +
                    def_node_matcher :capacity_keyword_argument?, <<~PATTERN
         | 
| 65 | 
            +
                      (hash (pair (sym :capacity) _))
         | 
| 55 66 | 
             
                    PATTERN
         | 
| 56 67 |  | 
| 57 68 | 
             
                    def on_send(node)
         | 
| @@ -4,8 +4,8 @@ module RuboCop | |
| 4 4 | 
             
              module Cop
         | 
| 5 5 | 
             
                module Lint
         | 
| 6 6 | 
             
                  # Checks for useless constant scoping. Private constants must be defined using
         | 
| 7 | 
            -
                  # `private_constant | 
| 8 | 
            -
                  #  | 
| 7 | 
            +
                  # `private_constant`. Even if `private` access modifier is used, it is public scope despite
         | 
| 8 | 
            +
                  # its appearance.
         | 
| 9 9 | 
             
                  #
         | 
| 10 10 | 
             
                  # It does not support autocorrection due to behavior change and multiple ways to fix it.
         | 
| 11 11 | 
             
                  # Or a public constant may be intended.
         | 
| @@ -26,14 +26,6 @@ module RuboCop | |
| 26 26 | 
             
                  #
         | 
| 27 27 | 
             
                  #   # good
         | 
| 28 28 | 
             
                  #   class Foo
         | 
| 29 | 
            -
                  #     class << self
         | 
| 30 | 
            -
                  #       private
         | 
| 31 | 
            -
                  #       PRIVATE_CONST = 42
         | 
| 32 | 
            -
                  #     end
         | 
| 33 | 
            -
                  #   end
         | 
| 34 | 
            -
                  #
         | 
| 35 | 
            -
                  #   # good
         | 
| 36 | 
            -
                  #   class Foo
         | 
| 37 29 | 
             
                  #     PUBLIC_CONST = 42 # If private scope is not intended.
         | 
| 38 30 | 
             
                  #   end
         | 
| 39 31 | 
             
                  #
         | 
| @@ -46,7 +38,6 @@ module RuboCop | |
| 46 38 | 
             
                    PATTERN
         | 
| 47 39 |  | 
| 48 40 | 
             
                    def on_casgn(node)
         | 
| 49 | 
            -
                      return if node.each_ancestor(:sclass).any?
         | 
| 50 41 | 
             
                      return unless after_private_modifier?(node.left_siblings)
         | 
| 51 42 | 
             
                      return if private_constantize?(node.right_siblings, node.name)
         | 
| 52 43 |  | 
| @@ -35,7 +35,7 @@ module RuboCop | |
| 35 35 | 
             
                    comment_line_numbers = processed_source.comments.map { |comment| comment.loc.line }
         | 
| 36 36 |  | 
| 37 37 | 
             
                    comment_line_numbers.any? do |comment_line_number|
         | 
| 38 | 
            -
                      comment_line_number | 
| 38 | 
            +
                      comment_line_number.between?(node.first_line, node.last_line)
         | 
| 39 39 | 
             
                    end
         | 
| 40 40 | 
             
                  end
         | 
| 41 41 |  | 
| @@ -34,6 +34,18 @@ module RuboCop | |
| 34 34 | 
             
                    range_between(node.loc.begin.end_pos, node.loc.end.begin_pos)
         | 
| 35 35 | 
             
                  end
         | 
| 36 36 |  | 
| 37 | 
            +
                  # A range containing the first to the last argument
         | 
| 38 | 
            +
                  # of a method call or method definition.
         | 
| 39 | 
            +
                  # def foo(a, b:)
         | 
| 40 | 
            +
                  #         ^^^^^
         | 
| 41 | 
            +
                  # bar(1, 2, 3, &blk)
         | 
| 42 | 
            +
                  #     ^^^^^^^^^^^^^
         | 
| 43 | 
            +
                  # baz { |x, y:, z:| }
         | 
| 44 | 
            +
                  #        ^^^^^^^^^
         | 
| 45 | 
            +
                  def arguments_range(node)
         | 
| 46 | 
            +
                    node.first_argument.source_range.join(node.last_argument.source_range)
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
             | 
| 37 49 | 
             
                  def range_between(start_pos, end_pos)
         | 
| 38 50 | 
             
                    Parser::Source::Range.new(processed_source.buffer, start_pos, end_pos)
         | 
| 39 51 | 
             
                  end
         |