rubocop 1.75.8 → 1.81.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +20 -16
 - data/config/default.yml +121 -28
 - data/config/obsoletion.yml +6 -3
 - data/exe/rubocop +1 -8
 - data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
 - data/lib/rubocop/cli.rb +18 -3
 - data/lib/rubocop/config_loader.rb +4 -39
 - data/lib/rubocop/config_loader_resolver.rb +5 -4
 - data/lib/rubocop/config_store.rb +5 -0
 - data/lib/rubocop/cop/autocorrect_logic.rb +4 -4
 - data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
 - data/lib/rubocop/cop/correctors/alignment_corrector.rb +7 -4
 - data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
 - data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
 - data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
 - data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
 - data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
 - data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
 - data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
 - data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
 - data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +4 -1
 - data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
 - data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
 - data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
 - data/lib/rubocop/cop/layout/class_structure.rb +1 -1
 - data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
 - data/lib/rubocop/cop/layout/dot_position.rb +1 -1
 - data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
 - data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
 - data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -1
 - data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
 - data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
 - data/lib/rubocop/cop/layout/hash_alignment.rb +2 -5
 - data/lib/rubocop/cop/layout/line_length.rb +35 -6
 - data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
 - data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +8 -0
 - data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
 - data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
 - data/lib/rubocop/cop/layout/space_before_brackets.rb +2 -9
 - data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
 - data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
 - data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
 - data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
 - data/lib/rubocop/cop/lint/cop_directive_syntax.rb +13 -7
 - data/lib/rubocop/cop/lint/debugger.rb +0 -2
 - data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
 - data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
 - data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
 - data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
 - data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
 - data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
 - data/lib/rubocop/cop/lint/literal_as_condition.rb +34 -28
 - data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +17 -8
 - data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
 - data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
 - data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
 - data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
 - data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
 - data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
 - data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
 - data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
 - data/lib/rubocop/cop/lint/self_assignment.rb +31 -5
 - data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
 - data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
 - data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
 - data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
 - data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
 - data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
 - data/lib/rubocop/cop/lint/useless_or.rb +98 -0
 - data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
 - data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
 - data/lib/rubocop/cop/lint/void.rb +7 -0
 - data/lib/rubocop/cop/message_annotator.rb +1 -1
 - data/lib/rubocop/cop/mixin/alignment.rb +1 -1
 - data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
 - data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
 - data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
 - data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
 - data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
 - data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
 - data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
 - data/lib/rubocop/cop/naming/file_name.rb +2 -2
 - data/lib/rubocop/cop/naming/method_name.rb +129 -13
 - data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
 - data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
 - data/lib/rubocop/cop/security/eval.rb +2 -1
 - data/lib/rubocop/cop/security/json_load.rb +33 -11
 - data/lib/rubocop/cop/security/open.rb +1 -0
 - data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
 - data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
 - data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
 - data/lib/rubocop/cop/style/array_intersect.rb +99 -35
 - data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
 - data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
 - data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
 - data/lib/rubocop/cop/style/case_like_if.rb +1 -1
 - data/lib/rubocop/cop/style/collection_querying.rb +167 -0
 - data/lib/rubocop/cop/style/conditional_assignment.rb +11 -5
 - data/lib/rubocop/cop/style/constant_visibility.rb +14 -9
 - data/lib/rubocop/cop/style/dig_chain.rb +1 -1
 - data/lib/rubocop/cop/style/double_negation.rb +1 -1
 - data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
 - data/lib/rubocop/cop/style/endless_method.rb +15 -2
 - data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
 - data/lib/rubocop/cop/style/exponential_notation.rb +3 -2
 - data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
 - data/lib/rubocop/cop/style/float_division.rb +15 -1
 - data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
 - data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
 - data/lib/rubocop/cop/style/if_unless_modifier.rb +13 -6
 - data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
 - data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
 - data/lib/rubocop/cop/style/it_assignment.rb +69 -12
 - data/lib/rubocop/cop/style/it_block_parameter.rb +36 -15
 - data/lib/rubocop/cop/style/map_to_hash.rb +1 -3
 - data/lib/rubocop/cop/style/map_to_set.rb +1 -3
 - data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -6
 - data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
 - data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
 - data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
 - data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
 - data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
 - data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
 - data/lib/rubocop/cop/style/redundant_begin.rb +34 -0
 - data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
 - data/lib/rubocop/cop/style/redundant_format.rb +26 -5
 - data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
 - data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_parentheses.rb +55 -16
 - data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
 - data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
 - data/lib/rubocop/cop/style/redundant_self.rb +8 -5
 - data/lib/rubocop/cop/style/safe_navigation.rb +44 -12
 - data/lib/rubocop/cop/style/semicolon.rb +23 -7
 - data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
 - data/lib/rubocop/cop/style/sole_nested_conditional.rb +40 -3
 - data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
 - data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
 - data/lib/rubocop/cop/style/symbol_array.rb +1 -1
 - data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
 - data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
 - data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
 - data/lib/rubocop/cop/style/unless_else.rb +10 -9
 - data/lib/rubocop/cop/utils/format_string.rb +10 -0
 - data/lib/rubocop/cop/variable_force/variable.rb +1 -1
 - data/lib/rubocop/cop/variable_force.rb +25 -8
 - data/lib/rubocop/cops_documentation_generator.rb +5 -4
 - data/lib/rubocop/formatter/disabled_config_formatter.rb +18 -5
 - data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
 - data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
 - data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
 - data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
 - data/lib/rubocop/lsp/diagnostic.rb +25 -24
 - data/lib/rubocop/lsp/routes.rb +65 -9
 - data/lib/rubocop/lsp/runtime.rb +2 -2
 - data/lib/rubocop/lsp/server.rb +2 -2
 - data/lib/rubocop/lsp/stdin_runner.rb +0 -16
 - data/lib/rubocop/pending_cops_reporter.rb +56 -0
 - data/lib/rubocop/result_cache.rb +14 -12
 - data/lib/rubocop/rspec/expect_offense.rb +9 -3
 - data/lib/rubocop/runner.rb +6 -4
 - data/lib/rubocop/server/cache.rb +4 -2
 - data/lib/rubocop/server/client_command/base.rb +10 -0
 - data/lib/rubocop/server/client_command/exec.rb +2 -1
 - data/lib/rubocop/server/client_command/start.rb +11 -1
 - data/lib/rubocop/target_finder.rb +9 -9
 - data/lib/rubocop/target_ruby.rb +10 -1
 - data/lib/rubocop/version.rb +1 -1
 - data/lib/rubocop.rb +12 -1
 - data/lib/ruby_lsp/rubocop/addon.rb +25 -10
 - data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
 - metadata +18 -7
 
| 
         @@ -56,12 +56,10 @@ module RuboCop 
     | 
|
| 
       56 
56 
     | 
    
         | 
| 
       57 
57 
     | 
    
         
             
                    def on_send(node)
         
     | 
| 
       58 
58 
     | 
    
         
             
                      return unless (to_h_node, map_node = map_to_h(node))
         
     | 
| 
      
 59 
     | 
    
         
            +
                      return if to_h_node.block_literal?
         
     | 
| 
       59 
60 
     | 
    
         | 
| 
       60 
61 
     | 
    
         
             
                      message = format(MSG, method: map_node.loc.selector.source, dot: to_h_node.loc.dot.source)
         
     | 
| 
       61 
62 
     | 
    
         
             
                      add_offense(map_node.loc.selector, message: message) do |corrector|
         
     | 
| 
       62 
     | 
    
         
            -
                        # If the `to_h` call already has a block, do not autocorrect.
         
     | 
| 
       63 
     | 
    
         
            -
                        next if to_h_node.block_literal?
         
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
63 
     | 
    
         
             
                        autocorrect(corrector, to_h_node, map_node)
         
     | 
| 
       66 
64 
     | 
    
         
             
                      end
         
     | 
| 
       67 
65 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -40,12 +40,10 @@ module RuboCop 
     | 
|
| 
       40 
40 
     | 
    
         | 
| 
       41 
41 
     | 
    
         
             
                    def on_send(node)
         
     | 
| 
       42 
42 
     | 
    
         
             
                      return unless (to_set_node, map_node = map_to_set?(node))
         
     | 
| 
      
 43 
     | 
    
         
            +
                      return if to_set_node.block_literal?
         
     | 
| 
       43 
44 
     | 
    
         | 
| 
       44 
45 
     | 
    
         
             
                      message = format(MSG, method: map_node.loc.selector.source)
         
     | 
| 
       45 
46 
     | 
    
         
             
                      add_offense(map_node.loc.selector, message: message) do |corrector|
         
     | 
| 
       46 
     | 
    
         
            -
                        # If the `to_set` call already has a block, do not autocorrect.
         
     | 
| 
       47 
     | 
    
         
            -
                        next if to_set_node.block_literal?
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
47 
     | 
    
         
             
                        autocorrect(corrector, to_set_node, map_node)
         
     | 
| 
       50 
48 
     | 
    
         
             
                      end
         
     | 
| 
       51 
49 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -167,7 +167,7 @@ module RuboCop 
     | 
|
| 
       167 
167 
     | 
    
         
             
                      def call_in_match_pattern?(node)
         
     | 
| 
       168 
168 
     | 
    
         
             
                        return false unless (parent = node.parent)
         
     | 
| 
       169 
169 
     | 
    
         | 
| 
       170 
     | 
    
         
            -
                        parent. 
     | 
| 
      
 170 
     | 
    
         
            +
                        parent.any_match_pattern_type?
         
     | 
| 
       171 
171 
     | 
    
         
             
                      end
         
     | 
| 
       172 
172 
     | 
    
         | 
| 
       173 
173 
     | 
    
         
             
                      def hash_literal_in_arguments?(node)
         
     | 
| 
         @@ -222,11 +222,9 @@ module RuboCop 
     | 
|
| 
       222 
222 
     | 
    
         
             
                      end
         
     | 
| 
       223 
223 
     | 
    
         | 
| 
       224 
224 
     | 
    
         
             
                      def unary_literal?(node)
         
     | 
| 
       225 
     | 
    
         
            -
                         
     | 
| 
       226 
     | 
    
         
            -
                        return node.source.match?(/\A[+-]/) if node.complex_type?
         
     | 
| 
      
 225 
     | 
    
         
            +
                        return true if node.numeric_type? && node.sign?
         
     | 
| 
       227 
226 
     | 
    
         | 
| 
       228 
     | 
    
         
            -
                         
     | 
| 
       229 
     | 
    
         
            -
                          (node.parent&.send_type? && node.parent.unary_operation?)
         
     | 
| 
      
 227 
     | 
    
         
            +
                        node.parent&.send_type? && node.parent.unary_operation?
         
     | 
| 
       230 
228 
     | 
    
         
             
                      end
         
     | 
| 
       231 
229 
     | 
    
         | 
| 
       232 
230 
     | 
    
         
             
                      def assigned_before?(node, target)
         
     | 
| 
         @@ -251,7 +249,7 @@ module RuboCop 
     | 
|
| 
       251 
249 
     | 
    
         
             
                        return false unless (last_argument = node.last_argument)
         
     | 
| 
       252 
250 
     | 
    
         
             
                        return true if last_argument.forwarded_restarg_type?
         
     | 
| 
       253 
251 
     | 
    
         | 
| 
       254 
     | 
    
         
            -
                        last_argument.hash_type? && last_argument.children. 
     | 
| 
      
 252 
     | 
    
         
            +
                        last_argument.hash_type? && last_argument.children.any?(&:forwarded_kwrestarg_type?)
         
     | 
| 
       255 
253 
     | 
    
         
             
                      end
         
     | 
| 
       256 
254 
     | 
    
         
             
                    end
         
     | 
| 
       257 
255 
     | 
    
         
             
                    # rubocop:enable Metrics/ModuleLength, Metrics/CyclomaticComplexity
         
     | 
| 
         @@ -132,6 +132,22 @@ module RuboCop 
     | 
|
| 
       132 
132 
     | 
    
         
             
                  #     bar :baz
         
     | 
| 
       133 
133 
     | 
    
         
             
                  #   end
         
     | 
| 
       134 
134 
     | 
    
         
             
                  #
         
     | 
| 
      
 135 
     | 
    
         
            +
                  # @example AllowedMethods: ["puts", "print"]
         
     | 
| 
      
 136 
     | 
    
         
            +
                  #
         
     | 
| 
      
 137 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 138 
     | 
    
         
            +
                  #   puts "Hello world"
         
     | 
| 
      
 139 
     | 
    
         
            +
                  #   print "Hello world"
         
     | 
| 
      
 140 
     | 
    
         
            +
                  #   # still enforces parentheses on other methods
         
     | 
| 
      
 141 
     | 
    
         
            +
                  #   array.delete(e)
         
     | 
| 
      
 142 
     | 
    
         
            +
                  #
         
     | 
| 
      
 143 
     | 
    
         
            +
                  # @example AllowedPatterns: ["^assert"]
         
     | 
| 
      
 144 
     | 
    
         
            +
                  #
         
     | 
| 
      
 145 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 146 
     | 
    
         
            +
                  #   assert_equal 'test', x
         
     | 
| 
      
 147 
     | 
    
         
            +
                  #   assert_match(/foo/, bar)
         
     | 
| 
      
 148 
     | 
    
         
            +
                  #   # still enforces parentheses on other methods
         
     | 
| 
      
 149 
     | 
    
         
            +
                  #   array.delete(e)
         
     | 
| 
      
 150 
     | 
    
         
            +
                  #
         
     | 
| 
       135 
151 
     | 
    
         
             
                  # @example AllowParenthesesInMultilineCall: false (default)
         
     | 
| 
       136 
152 
     | 
    
         
             
                  #
         
     | 
| 
       137 
153 
     | 
    
         
             
                  #   # bad
         
     | 
| 
         @@ -39,13 +39,21 @@ module RuboCop 
     | 
|
| 
       39 
39 
     | 
    
         
             
                    include RangeHelp
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
       41 
41 
     | 
    
         
             
                    MSG = 'Use `%<prefer>s` instead.'
         
     | 
| 
       42 
     | 
    
         
            -
                     
     | 
| 
      
 42 
     | 
    
         
            +
                    GREATER_OPERATORS = %i[> >=].freeze
         
     | 
| 
       43 
43 
     | 
    
         
             
                    LESS_OPERATORS = %i[< <=].freeze
         
     | 
| 
       44 
     | 
    
         
            -
                    COMPARISON_OPERATORS =  
     | 
| 
      
 44 
     | 
    
         
            +
                    COMPARISON_OPERATORS = (GREATER_OPERATORS + LESS_OPERATORS).to_set.freeze
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    # @!method comparison_condition(node, name)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    def_node_matcher :comparison_condition, <<~PATTERN
         
     | 
| 
      
 48 
     | 
    
         
            +
                      {
         
     | 
| 
      
 49 
     | 
    
         
            +
                        (send $_lhs $COMPARISON_OPERATORS $_rhs)
         
     | 
| 
      
 50 
     | 
    
         
            +
                        (begin (send $_lhs $COMPARISON_OPERATORS $_rhs))
         
     | 
| 
      
 51 
     | 
    
         
            +
                      }
         
     | 
| 
      
 52 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
       45 
53 
     | 
    
         | 
| 
       46 
54 
     | 
    
         
             
                    def on_if(node)
         
     | 
| 
       47 
     | 
    
         
            -
                      lhs, operator, rhs =  
     | 
| 
       48 
     | 
    
         
            -
                      return unless  
     | 
| 
      
 55 
     | 
    
         
            +
                      lhs, operator, rhs = comparison_condition(node.condition)
         
     | 
| 
      
 56 
     | 
    
         
            +
                      return unless operator
         
     | 
| 
       49 
57 
     | 
    
         | 
| 
       50 
58 
     | 
    
         
             
                      if_branch = node.if_branch
         
     | 
| 
       51 
59 
     | 
    
         
             
                      else_branch = node.else_branch
         
     | 
| 
         @@ -63,7 +71,7 @@ module RuboCop 
     | 
|
| 
       63 
71 
     | 
    
         | 
| 
       64 
72 
     | 
    
         
             
                    def preferred_method(operator, lhs, rhs, if_branch, else_branch)
         
     | 
| 
       65 
73 
     | 
    
         
             
                      if lhs == if_branch && rhs == else_branch
         
     | 
| 
       66 
     | 
    
         
            -
                         
     | 
| 
      
 74 
     | 
    
         
            +
                        GREATER_OPERATORS.include?(operator) ? 'max' : 'min'
         
     | 
| 
       67 
75 
     | 
    
         
             
                      elsif lhs == else_branch && rhs == if_branch
         
     | 
| 
       68 
76 
     | 
    
         
             
                        LESS_OPERATORS.include?(operator) ? 'max' : 'min'
         
     | 
| 
       69 
77 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -43,24 +43,26 @@ module RuboCop 
     | 
|
| 
       43 
43 
     | 
    
         
             
                    # @!method nil_check?(node)
         
     | 
| 
       44 
44 
     | 
    
         
             
                    def_node_matcher :nil_check?, '(send _ :nil?)'
         
     | 
| 
       45 
45 
     | 
    
         | 
| 
      
 46 
     | 
    
         
            +
                    # rubocop:disable Metrics/AbcSize
         
     | 
| 
       46 
47 
     | 
    
         
             
                    def on_send(node)
         
     | 
| 
       47 
48 
     | 
    
         
             
                      return unless node.receiver
         
     | 
| 
       48 
49 
     | 
    
         | 
| 
       49 
50 
     | 
    
         
             
                      style_check?(node) do
         
     | 
| 
       50 
51 
     | 
    
         
             
                        add_offense(node.loc.selector) do |corrector|
         
     | 
| 
       51 
     | 
    
         
            -
                           
     | 
| 
       52 
     | 
    
         
            -
             
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
                           
     | 
| 
      
 52 
     | 
    
         
            +
                          if prefer_comparison?
         
     | 
| 
      
 53 
     | 
    
         
            +
                            range = node.loc.dot.join(node.loc.selector.end)
         
     | 
| 
      
 54 
     | 
    
         
            +
                            corrector.replace(range, ' == nil')
         
     | 
| 
      
 55 
     | 
    
         
            +
                          else
         
     | 
| 
      
 56 
     | 
    
         
            +
                            range = node.receiver.source_range.end.join(node.source_range.end)
         
     | 
| 
      
 57 
     | 
    
         
            +
                            corrector.replace(range, '.nil?')
         
     | 
| 
      
 58 
     | 
    
         
            +
                          end
         
     | 
| 
       58 
59 
     | 
    
         | 
| 
       59 
60 
     | 
    
         
             
                          parent = node.parent
         
     | 
| 
       60 
61 
     | 
    
         
             
                          corrector.wrap(node, '(', ')') if parent.respond_to?(:method?) && parent.method?(:!)
         
     | 
| 
       61 
62 
     | 
    
         
             
                        end
         
     | 
| 
       62 
63 
     | 
    
         
             
                      end
         
     | 
| 
       63 
64 
     | 
    
         
             
                    end
         
     | 
| 
      
 65 
     | 
    
         
            +
                    # rubocop:enable Metrics/AbcSize
         
     | 
| 
       64 
66 
     | 
    
         | 
| 
       65 
67 
     | 
    
         
             
                    private
         
     | 
| 
       66 
68 
     | 
    
         | 
| 
         @@ -55,19 +55,21 @@ module RuboCop 
     | 
|
| 
       55 
55 
     | 
    
         
             
                    include OnNormalIfUnless
         
     | 
| 
       56 
56 
     | 
    
         
             
                    extend AutoCorrector
         
     | 
| 
       57 
57 
     | 
    
         | 
| 
       58 
     | 
    
         
            -
                     
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
      
 58 
     | 
    
         
            +
                    MSG_SUFFIX = 'over single-line `%<keyword>s/then/else/end` constructs.'
         
     | 
| 
      
 59 
     | 
    
         
            +
                    MSG_TERNARY = "Favor the ternary operator (`?:`) #{MSG_SUFFIX}"
         
     | 
| 
      
 60 
     | 
    
         
            +
                    MSG_MULTILINE = "Favor multi-line `%<keyword>s` #{MSG_SUFFIX}"
         
     | 
| 
       60 
61 
     | 
    
         | 
| 
       61 
62 
     | 
    
         
             
                    def on_normal_if_unless(node)
         
     | 
| 
       62 
63 
     | 
    
         
             
                      return unless node.single_line?
         
     | 
| 
       63 
64 
     | 
    
         
             
                      return unless node.else_branch
         
     | 
| 
       64 
65 
     | 
    
         
             
                      return if node.elsif? || node.if_branch&.begin_type?
         
     | 
| 
       65 
66 
     | 
    
         | 
| 
       66 
     | 
    
         
            -
                       
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
      
 67 
     | 
    
         
            +
                      multiline = multiline?(node)
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                      add_offense(node, message: message(node, multiline)) do |corrector|
         
     | 
| 
       68 
70 
     | 
    
         
             
                        next if part_of_ignored_node?(node)
         
     | 
| 
       69 
71 
     | 
    
         | 
| 
       70 
     | 
    
         
            -
                        autocorrect(corrector, node)
         
     | 
| 
      
 72 
     | 
    
         
            +
                        autocorrect(corrector, node, multiline)
         
     | 
| 
       71 
73 
     | 
    
         | 
| 
       72 
74 
     | 
    
         
             
                        ignore_node(node)
         
     | 
| 
       73 
75 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -75,12 +77,18 @@ module RuboCop 
     | 
|
| 
       75 
77 
     | 
    
         | 
| 
       76 
78 
     | 
    
         
             
                    private
         
     | 
| 
       77 
79 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
                    def  
     | 
| 
       79 
     | 
    
         
            -
                       
     | 
| 
      
 80 
     | 
    
         
            +
                    def multiline?(node)
         
     | 
| 
      
 81 
     | 
    
         
            +
                      always_multiline? || cannot_replace_to_ternary?(node)
         
     | 
| 
      
 82 
     | 
    
         
            +
                    end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                    def message(node, multiline)
         
     | 
| 
      
 85 
     | 
    
         
            +
                      template = multiline ? MSG_MULTILINE : MSG_TERNARY
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                      format(template, keyword: node.keyword)
         
     | 
| 
       80 
88 
     | 
    
         
             
                    end
         
     | 
| 
       81 
89 
     | 
    
         | 
| 
       82 
     | 
    
         
            -
                    def autocorrect(corrector, node)
         
     | 
| 
       83 
     | 
    
         
            -
                      if  
     | 
| 
      
 90 
     | 
    
         
            +
                    def autocorrect(corrector, node, multiline)
         
     | 
| 
      
 91 
     | 
    
         
            +
                      if multiline
         
     | 
| 
       84 
92 
     | 
    
         
             
                        IfThenCorrector.new(node, indentation: configured_indentation_width).call(corrector)
         
     | 
| 
       85 
93 
     | 
    
         
             
                      else
         
     | 
| 
       86 
94 
     | 
    
         
             
                        corrector.replace(node, ternary_correction(node))
         
     | 
| 
         @@ -1,7 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require 'tsort'
         
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
3 
     | 
    
         
             
            module RuboCop
         
     | 
| 
       6 
4 
     | 
    
         
             
              module Cop
         
     | 
| 
       7 
5 
     | 
    
         
             
                module Style
         
     | 
| 
         @@ -29,6 +27,8 @@ module RuboCop 
     | 
|
| 
       29 
27 
     | 
    
         
             
                    MSG = 'Do not use parallel assignment.'
         
     | 
| 
       30 
28 
     | 
    
         | 
| 
       31 
29 
     | 
    
         
             
                    def on_masgn(node) # rubocop:disable Metrics/AbcSize
         
     | 
| 
      
 30 
     | 
    
         
            +
                      return if part_of_ignored_node?(node)
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
       32 
32 
     | 
    
         
             
                      rhs = node.rhs
         
     | 
| 
       33 
33 
     | 
    
         
             
                      rhs = rhs.body if rhs.rescue_type?
         
     | 
| 
       34 
34 
     | 
    
         
             
                      rhs_elements = Array(rhs).compact # edge case for one constant
         
     | 
| 
         @@ -41,6 +41,7 @@ module RuboCop 
     | 
|
| 
       41 
41 
     | 
    
         
             
                      add_offense(range) do |corrector|
         
     | 
| 
       42 
42 
     | 
    
         
             
                        autocorrect(corrector, node, rhs)
         
     | 
| 
       43 
43 
     | 
    
         
             
                      end
         
     | 
| 
      
 44 
     | 
    
         
            +
                      ignore_node(node)
         
     | 
| 
       44 
45 
     | 
    
         
             
                    end
         
     | 
| 
       45 
46 
     | 
    
         | 
| 
       46 
47 
     | 
    
         
             
                    private
         
     | 
| 
         @@ -91,15 +92,9 @@ module RuboCop 
     | 
|
| 
       91 
92 
     | 
    
         
             
                    def find_valid_order(left_elements, right_elements)
         
     | 
| 
       92 
93 
     | 
    
         
             
                      # arrange left_elements in an order such that no corresponding right
         
     | 
| 
       93 
94 
     | 
    
         
             
                      # element refers to a left element earlier in the sequence
         
     | 
| 
       94 
     | 
    
         
            -
                      # this can be done using an algorithm called a "topological sort"
         
     | 
| 
       95 
     | 
    
         
            -
                      # fortunately for us, Ruby's stdlib contains an implementation
         
     | 
| 
       96 
95 
     | 
    
         
             
                      assignments = left_elements.zip(right_elements)
         
     | 
| 
       97 
96 
     | 
    
         | 
| 
       98 
     | 
    
         
            -
                       
     | 
| 
       99 
     | 
    
         
            -
                        AssignmentSorter.new(assignments).tsort
         
     | 
| 
       100 
     | 
    
         
            -
                      rescue TSort::Cyclic
         
     | 
| 
       101 
     | 
    
         
            -
                        nil
         
     | 
| 
       102 
     | 
    
         
            -
                      end
         
     | 
| 
      
 97 
     | 
    
         
            +
                      AssignmentSorter.new(assignments).tsort
         
     | 
| 
       103 
98 
     | 
    
         
             
                    end
         
     | 
| 
       104 
99 
     | 
    
         | 
| 
       105 
100 
     | 
    
         
             
                    # Converts (send nil :something) nodes to (send (:self) :something).
         
     | 
| 
         @@ -114,10 +109,9 @@ module RuboCop 
     | 
|
| 
       114 
109 
     | 
    
         
             
                    # @!method implicit_self_getter?(node)
         
     | 
| 
       115 
110 
     | 
    
         
             
                    def_node_matcher :implicit_self_getter?, '(send nil? $_)'
         
     | 
| 
       116 
111 
     | 
    
         | 
| 
       117 
     | 
    
         
            -
                    #  
     | 
| 
       118 
     | 
    
         
            -
                    #  
     | 
| 
      
 112 
     | 
    
         
            +
                    # Topologically sorts the assignments with Kahn's algorithm.
         
     | 
| 
      
 113 
     | 
    
         
            +
                    # https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm
         
     | 
| 
       119 
114 
     | 
    
         
             
                    class AssignmentSorter
         
     | 
| 
       120 
     | 
    
         
            -
                      include TSort
         
     | 
| 
       121 
115 
     | 
    
         
             
                      extend RuboCop::NodePattern::Macros
         
     | 
| 
       122 
116 
     | 
    
         | 
| 
       123 
117 
     | 
    
         
             
                      # @!method var_name(node)
         
     | 
| 
         @@ -133,21 +127,39 @@ module RuboCop 
     | 
|
| 
       133 
127 
     | 
    
         
             
                        @assignments = assignments
         
     | 
| 
       134 
128 
     | 
    
         
             
                      end
         
     | 
| 
       135 
129 
     | 
    
         | 
| 
       136 
     | 
    
         
            -
                      def  
     | 
| 
       137 
     | 
    
         
            -
                        @assignments. 
     | 
| 
      
 130 
     | 
    
         
            +
                      def tsort
         
     | 
| 
      
 131 
     | 
    
         
            +
                        dependencies = @assignments.to_h do |assignment|
         
     | 
| 
      
 132 
     | 
    
         
            +
                          [assignment, dependencies_for_assignment(assignment)]
         
     | 
| 
      
 133 
     | 
    
         
            +
                        end
         
     | 
| 
      
 134 
     | 
    
         
            +
                        result = []
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                        while (matched_node, = dependencies.find { |_node, edges| edges.empty? })
         
     | 
| 
      
 137 
     | 
    
         
            +
                          dependencies.delete(matched_node)
         
     | 
| 
      
 138 
     | 
    
         
            +
                          result.push(matched_node)
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                          dependencies.each do |node, edges|
         
     | 
| 
      
 141 
     | 
    
         
            +
                            dependencies[node].delete(matched_node) if edges.include?(matched_node)
         
     | 
| 
      
 142 
     | 
    
         
            +
                          end
         
     | 
| 
      
 143 
     | 
    
         
            +
                        end
         
     | 
| 
      
 144 
     | 
    
         
            +
                        # Cyclic dependency
         
     | 
| 
      
 145 
     | 
    
         
            +
                        return nil if dependencies.any?
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                        result
         
     | 
| 
       138 
148 
     | 
    
         
             
                      end
         
     | 
| 
       139 
149 
     | 
    
         | 
| 
       140 
     | 
    
         
            -
                       
     | 
| 
       141 
     | 
    
         
            -
             
     | 
| 
       142 
     | 
    
         
            -
             
     | 
| 
      
 150 
     | 
    
         
            +
                      # Returns all the assignments which must come after `assignment`
         
     | 
| 
      
 151 
     | 
    
         
            +
                      # (due to dependencies on the previous value of the assigned var)
         
     | 
| 
      
 152 
     | 
    
         
            +
                      def dependencies_for_assignment(assignment)
         
     | 
| 
       143 
153 
     | 
    
         
             
                        my_lhs, _my_rhs = *assignment
         
     | 
| 
       144 
154 
     | 
    
         | 
| 
       145 
     | 
    
         
            -
                        @assignments. 
     | 
| 
       146 
     | 
    
         
            -
                           
     | 
| 
      
 155 
     | 
    
         
            +
                        @assignments.filter_map do |other|
         
     | 
| 
      
 156 
     | 
    
         
            +
                          # Exclude self, there are no dependencies in cases such as `a, b = a, b`.
         
     | 
| 
      
 157 
     | 
    
         
            +
                          next if other == assignment
         
     | 
| 
       147 
158 
     | 
    
         | 
| 
      
 159 
     | 
    
         
            +
                          _other_lhs, other_rhs = *other
         
     | 
| 
       148 
160 
     | 
    
         
             
                          next unless dependency?(my_lhs, other_rhs)
         
     | 
| 
       149 
161 
     | 
    
         | 
| 
       150 
     | 
    
         
            -
                           
     | 
| 
      
 162 
     | 
    
         
            +
                          other
         
     | 
| 
       151 
163 
     | 
    
         
             
                        end
         
     | 
| 
       152 
164 
     | 
    
         
             
                      end
         
     | 
| 
       153 
165 
     | 
    
         | 
| 
         @@ -0,0 +1,50 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Style
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # Checks for redundant calls of `Array#flatten`.
         
     | 
| 
      
 7 
     | 
    
         
            +
                  #
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # `Array#join` joins nested arrays recursively, so flattening an array
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # beforehand is redundant.
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # @safety
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #   Cop is unsafe because the receiver of `flatten` method might not
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #   be an `Array`, so it's possible it won't respond to `join` method,
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #   or the end result would be different.
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #   Also, if the global variable `$,` is set to a value other than the default `nil`,
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #   false positives may occur.
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # @example
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #   x.flatten.join
         
     | 
| 
      
 21 
     | 
    
         
            +
                  #   x.flatten(1).join
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #   x.join
         
     | 
| 
      
 25 
     | 
    
         
            +
                  #
         
     | 
| 
      
 26 
     | 
    
         
            +
                  class RedundantArrayFlatten < Base
         
     | 
| 
      
 27 
     | 
    
         
            +
                    extend AutoCorrector
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    MSG = 'Remove the redundant `flatten`.'
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    RESTRICT_ON_SEND = %i[flatten].freeze
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    # @!method flatten_join?(node)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    def_node_matcher :flatten_join?, <<~PATTERN
         
     | 
| 
      
 35 
     | 
    
         
            +
                      (call (call !nil? :flatten _?) :join (nil)?)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                    def on_send(node)
         
     | 
| 
      
 39 
     | 
    
         
            +
                      return unless flatten_join?(node.parent)
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                      range = node.loc.dot.begin.join(node.source_range.end)
         
     | 
| 
      
 42 
     | 
    
         
            +
                      add_offense(range) do |corrector|
         
     | 
| 
      
 43 
     | 
    
         
            +
                        corrector.remove(range)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      end
         
     | 
| 
      
 45 
     | 
    
         
            +
                    end
         
     | 
| 
      
 46 
     | 
    
         
            +
                    alias on_csend on_send
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
              end
         
     | 
| 
      
 50 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -85,6 +85,29 @@ module RuboCop 
     | 
|
| 
       85 
85 
     | 
    
         
             
                    end
         
     | 
| 
       86 
86 
     | 
    
         
             
                    alias on_defs on_def
         
     | 
| 
       87 
87 
     | 
    
         | 
| 
      
 88 
     | 
    
         
            +
                    def on_if(node)
         
     | 
| 
      
 89 
     | 
    
         
            +
                      return if node.modifier_form?
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                      inspect_branches(node)
         
     | 
| 
      
 92 
     | 
    
         
            +
                    end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                    def on_case(node)
         
     | 
| 
      
 95 
     | 
    
         
            +
                      inspect_branches(node)
         
     | 
| 
      
 96 
     | 
    
         
            +
                    end
         
     | 
| 
      
 97 
     | 
    
         
            +
                    alias on_case_match on_case
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                    def on_while(node)
         
     | 
| 
      
 100 
     | 
    
         
            +
                      return if node.modifier_form?
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                      body = node.body
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                      return unless body&.kwbegin_type?
         
     | 
| 
      
 105 
     | 
    
         
            +
                      return if body.rescue_node || body.ensure_node
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                      register_offense(body)
         
     | 
| 
      
 108 
     | 
    
         
            +
                    end
         
     | 
| 
      
 109 
     | 
    
         
            +
                    alias on_until on_while
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
       88 
111 
     | 
    
         
             
                    def on_block(node)
         
     | 
| 
       89 
112 
     | 
    
         
             
                      return if target_ruby_version < 2.5
         
     | 
| 
       90 
113 
     | 
    
         
             
                      return if node.send_node.lambda_literal?
         
     | 
| 
         @@ -180,6 +203,8 @@ module RuboCop 
     | 
|
| 
       180 
203 
     | 
    
         
             
                    end
         
     | 
| 
       181 
204 
     | 
    
         | 
| 
       182 
205 
     | 
    
         
             
                    def begin_block_has_multiline_statements?(node)
         
     | 
| 
      
 206 
     | 
    
         
            +
                      return false unless node.parent
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
       183 
208 
     | 
    
         
             
                      node.children.count >= 2
         
     | 
| 
       184 
209 
     | 
    
         
             
                    end
         
     | 
| 
       185 
210 
     | 
    
         | 
| 
         @@ -199,6 +224,15 @@ module RuboCop 
     | 
|
| 
       199 
224 
     | 
    
         
             
                    def valid_begin_assignment?(node)
         
     | 
| 
       200 
225 
     | 
    
         
             
                      node.parent&.assignment? && !node.children.one?
         
     | 
| 
       201 
226 
     | 
    
         
             
                    end
         
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
                    def inspect_branches(node)
         
     | 
| 
      
 229 
     | 
    
         
            +
                      node.branches.each do |branch|
         
     | 
| 
      
 230 
     | 
    
         
            +
                        next unless branch&.kwbegin_type?
         
     | 
| 
      
 231 
     | 
    
         
            +
                        next if branch.rescue_node || branch.ensure_node
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
                        register_offense(branch)
         
     | 
| 
      
 234 
     | 
    
         
            +
                      end
         
     | 
| 
      
 235 
     | 
    
         
            +
                    end
         
     | 
| 
       202 
236 
     | 
    
         
             
                  end
         
     | 
| 
       203 
237 
     | 
    
         
             
                end
         
     | 
| 
       204 
238 
     | 
    
         
             
              end
         
     | 
| 
         @@ -247,7 +247,7 @@ module RuboCop 
     | 
|
| 
       247 
247 
     | 
    
         
             
                        "#{if_branch.receiver.source} #{if_branch.method_name} (#{argument_source}"
         
     | 
| 
       248 
248 
     | 
    
         
             
                      elsif if_branch.true_type?
         
     | 
| 
       249 
249 
     | 
    
         
             
                        condition = if_branch.parent.condition
         
     | 
| 
       250 
     | 
    
         
            -
                        return condition.source if condition.arguments.empty?
         
     | 
| 
      
 250 
     | 
    
         
            +
                        return condition.source if condition.arguments.empty? || condition.parenthesized?
         
     | 
| 
       251 
251 
     | 
    
         | 
| 
       252 
252 
     | 
    
         
             
                        wrap_arguments_with_parens(condition)
         
     | 
| 
       253 
253 
     | 
    
         
             
                      else
         
     | 
| 
         @@ -49,7 +49,7 @@ module RuboCop 
     | 
|
| 
       49 
49 
     | 
    
         
             
                      (block
         
     | 
| 
       50 
50 
     | 
    
         
             
                        $(call _ :fetch _)
         
     | 
| 
       51 
51 
     | 
    
         
             
                        (args)
         
     | 
| 
       52 
     | 
    
         
            -
                        ${nil?  
     | 
| 
      
 52 
     | 
    
         
            +
                        ${nil? basic_literal? const_type?})
         
     | 
| 
       53 
53 
     | 
    
         
             
                    PATTERN
         
     | 
| 
       54 
54 
     | 
    
         | 
| 
       55 
55 
     | 
    
         
             
                    def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
         
     | 
| 
         @@ -71,14 +71,6 @@ module RuboCop 
     | 
|
| 
       71 
71 
     | 
    
         | 
| 
       72 
72 
     | 
    
         
             
                    private
         
     | 
| 
       73 
73 
     | 
    
         | 
| 
       74 
     | 
    
         
            -
                    def basic_literal?(node)
         
     | 
| 
       75 
     | 
    
         
            -
                      node&.basic_literal?
         
     | 
| 
       76 
     | 
    
         
            -
                    end
         
     | 
| 
       77 
     | 
    
         
            -
             
     | 
| 
       78 
     | 
    
         
            -
                    def const_type?(node)
         
     | 
| 
       79 
     | 
    
         
            -
                      node&.const_type?
         
     | 
| 
       80 
     | 
    
         
            -
                    end
         
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
74 
     | 
    
         
             
                    def should_not_check?(send, body)
         
     | 
| 
       83 
75 
     | 
    
         
             
                      (body&.const_type? && !check_for_constant?) ||
         
     | 
| 
       84 
76 
     | 
    
         
             
                        (body&.str_type? && !check_for_string?) ||
         
     | 
| 
         @@ -89,7 +89,7 @@ module RuboCop 
     | 
|
| 
       89 
89 
     | 
    
         | 
| 
       90 
90 
     | 
    
         
             
                    def on_send(node)
         
     | 
| 
       91 
91 
     | 
    
         
             
                      format_without_additional_args?(node) do |value|
         
     | 
| 
       92 
     | 
    
         
            -
                        replacement = value.source
         
     | 
| 
      
 92 
     | 
    
         
            +
                        replacement = escape_control_chars(value.source)
         
     | 
| 
       93 
93 
     | 
    
         | 
| 
       94 
94 
     | 
    
         
             
                        add_offense(node, message: message(node, replacement)) do |corrector|
         
     | 
| 
       95 
95 
     | 
    
         
             
                          corrector.replace(node, replacement)
         
     | 
| 
         @@ -134,6 +134,7 @@ module RuboCop 
     | 
|
| 
       134 
134 
     | 
    
         
             
                      end
         
     | 
| 
       135 
135 
     | 
    
         
             
                    end
         
     | 
| 
       136 
136 
     | 
    
         | 
| 
      
 137 
     | 
    
         
            +
                    # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
         
     | 
| 
       137 
138 
     | 
    
         
             
                    def all_fields_literal?(string, arguments)
         
     | 
| 
       138 
139 
     | 
    
         
             
                      count = 0
         
     | 
| 
       139 
140 
     | 
    
         
             
                      sequences = RuboCop::Cop::Utils::FormatString.new(string).format_sequences
         
     | 
| 
         @@ -141,29 +142,44 @@ module RuboCop 
     | 
|
| 
       141 
142 
     | 
    
         | 
| 
       142 
143 
     | 
    
         
             
                      sequences.each do |sequence|
         
     | 
| 
       143 
144 
     | 
    
         
             
                        next if sequence.percent?
         
     | 
| 
      
 145 
     | 
    
         
            +
                        next if unknown_variable_width?(sequence, arguments)
         
     | 
| 
       144 
146 
     | 
    
         | 
| 
       145 
147 
     | 
    
         
             
                        hash = arguments.detect(&:hash_type?)
         
     | 
| 
       146 
148 
     | 
    
         
             
                        next unless (argument = find_argument(sequence, arguments, hash))
         
     | 
| 
       147 
149 
     | 
    
         
             
                        next unless matching_argument?(sequence, argument)
         
     | 
| 
      
 150 
     | 
    
         
            +
                        next if (sequence.width || sequence.precision) && argument.dstr_type?
         
     | 
| 
       148 
151 
     | 
    
         | 
| 
       149 
152 
     | 
    
         
             
                        count += 1
         
     | 
| 
       150 
153 
     | 
    
         
             
                      end
         
     | 
| 
       151 
154 
     | 
    
         | 
| 
       152 
155 
     | 
    
         
             
                      sequences.size == count
         
     | 
| 
       153 
156 
     | 
    
         
             
                    end
         
     | 
| 
      
 157 
     | 
    
         
            +
                    # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
         
     | 
| 
       154 
158 
     | 
    
         | 
| 
      
 159 
     | 
    
         
            +
                    # If the sequence has a variable (`*`) width, it cannot be autocorrected
         
     | 
| 
      
 160 
     | 
    
         
            +
                    # if the width is not given as a numeric literal argument
         
     | 
| 
      
 161 
     | 
    
         
            +
                    def unknown_variable_width?(sequence, arguments)
         
     | 
| 
      
 162 
     | 
    
         
            +
                      return false unless sequence.variable_width?
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                      argument = arguments[sequence.variable_width_argument_number - 1]
         
     | 
| 
      
 165 
     | 
    
         
            +
                      !numeric?(argument)
         
     | 
| 
      
 166 
     | 
    
         
            +
                    end
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                    # rubocop:disable Metrics/AbcSize
         
     | 
| 
       155 
169 
     | 
    
         
             
                    def find_argument(sequence, arguments, hash)
         
     | 
| 
       156 
170 
     | 
    
         
             
                      if hash && (sequence.annotated? || sequence.template?)
         
     | 
| 
       157 
171 
     | 
    
         
             
                        find_hash_value_node(hash, sequence.name.to_sym).first
         
     | 
| 
      
 172 
     | 
    
         
            +
                      elsif sequence.variable_width?
         
     | 
| 
      
 173 
     | 
    
         
            +
                        # If the specifier contains `*`, the argument for the width can be ignored.
         
     | 
| 
      
 174 
     | 
    
         
            +
                        arguments.delete_at(sequence.variable_width_argument_number - 1)
         
     | 
| 
      
 175 
     | 
    
         
            +
                        arguments.shift
         
     | 
| 
       158 
176 
     | 
    
         
             
                      elsif sequence.arg_number
         
     | 
| 
       159 
177 
     | 
    
         
             
                        arguments[sequence.arg_number.to_i - 1]
         
     | 
| 
       160 
178 
     | 
    
         
             
                      else
         
     | 
| 
       161 
     | 
    
         
            -
                        # If the specifier contains `*`, the following arguments will be used
         
     | 
| 
       162 
     | 
    
         
            -
                        # to specify the width and can be ignored.
         
     | 
| 
       163 
     | 
    
         
            -
                        (sequence.arity - 1).times { arguments.shift }
         
     | 
| 
       164 
179 
     | 
    
         
             
                        arguments.shift
         
     | 
| 
       165 
180 
     | 
    
         
             
                      end
         
     | 
| 
       166 
181 
     | 
    
         
             
                    end
         
     | 
| 
      
 182 
     | 
    
         
            +
                    # rubocop:enable Metrics/AbcSize
         
     | 
| 
       167 
183 
     | 
    
         | 
| 
       168 
184 
     | 
    
         
             
                    def matching_argument?(sequence, argument)
         
     | 
| 
       169 
185 
     | 
    
         
             
                      # Template specifiers don't give a type, any acceptable literal type is ok.
         
     | 
| 
         @@ -214,7 +230,12 @@ module RuboCop 
     | 
|
| 
       214 
230 
     | 
    
         
             
                        end
         
     | 
| 
       215 
231 
     | 
    
         
             
                      end
         
     | 
| 
       216 
232 
     | 
    
         | 
| 
       217 
     | 
    
         
            -
                      "#{start_delimiter}#{string}#{end_delimiter}"
         
     | 
| 
      
 233 
     | 
    
         
            +
                      "#{start_delimiter}#{escape_control_chars(string)}#{end_delimiter}"
         
     | 
| 
      
 234 
     | 
    
         
            +
                    end
         
     | 
| 
      
 235 
     | 
    
         
            +
             
     | 
| 
      
 236 
     | 
    
         
            +
                    # Escape any control characters in the string (eg. `\t` or `\n` become `\\t` or `\\n`)
         
     | 
| 
      
 237 
     | 
    
         
            +
                    def escape_control_chars(string)
         
     | 
| 
      
 238 
     | 
    
         
            +
                      string.gsub(/\p{Cc}/) { |s| s.dump[1..-2] }
         
     | 
| 
       218 
239 
     | 
    
         
             
                    end
         
     | 
| 
       219 
240 
     | 
    
         | 
| 
       220 
241 
     | 
    
         
             
                    def argument_values(arguments)
         
     | 
| 
         @@ -49,9 +49,10 @@ module RuboCop 
     | 
|
| 
       49 
49 
     | 
    
         
             
                    def on_dstr(node)
         
     | 
| 
       50 
50 
     | 
    
         
             
                      return unless single_interpolation?(node)
         
     | 
| 
       51 
51 
     | 
    
         | 
| 
       52 
     | 
    
         
            -
                       
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
      
 52 
     | 
    
         
            +
                      embedded_node = node.children.first
         
     | 
| 
      
 53 
     | 
    
         
            +
                      return if use_match_pattern?(embedded_node)
         
     | 
| 
       54 
54 
     | 
    
         | 
| 
      
 55 
     | 
    
         
            +
                      add_offense(node) do |corrector|
         
     | 
| 
       55 
56 
     | 
    
         
             
                        if variable_interpolation?(embedded_node)
         
     | 
| 
       56 
57 
     | 
    
         
             
                          autocorrect_variable_interpolation(corrector, embedded_node, node)
         
     | 
| 
       57 
58 
     | 
    
         
             
                        elsif single_variable_interpolation?(embedded_node)
         
     | 
| 
         @@ -71,6 +72,14 @@ module RuboCop 
     | 
|
| 
       71 
72 
     | 
    
         
             
                        !embedded_in_percent_array?(node)
         
     | 
| 
       72 
73 
     | 
    
         
             
                    end
         
     | 
| 
       73 
74 
     | 
    
         | 
| 
      
 75 
     | 
    
         
            +
                    def use_match_pattern?(node)
         
     | 
| 
      
 76 
     | 
    
         
            +
                      return false if target_ruby_version <= 2.7
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                      node.children.any? do |child|
         
     | 
| 
      
 79 
     | 
    
         
            +
                        child.respond_to?(:match_pattern_type?) && child.match_pattern_type?
         
     | 
| 
      
 80 
     | 
    
         
            +
                      end
         
     | 
| 
      
 81 
     | 
    
         
            +
                    end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
       74 
83 
     | 
    
         
             
                    def single_variable_interpolation?(node)
         
     | 
| 
       75 
84 
     | 
    
         
             
                      return false unless node.children.one?
         
     | 
| 
       76 
85 
     | 
    
         | 
| 
         @@ -130,7 +139,7 @@ module RuboCop 
     | 
|
| 
       130 
139 
     | 
    
         
             
                    end
         
     | 
| 
       131 
140 
     | 
    
         | 
| 
       132 
141 
     | 
    
         
             
                    def require_parentheses?(node)
         
     | 
| 
       133 
     | 
    
         
            -
                      node.send_type? &&  
     | 
| 
      
 142 
     | 
    
         
            +
                      node.send_type? && node.arguments.any? && !node.parenthesized_call?
         
     | 
| 
       134 
143 
     | 
    
         
             
                    end
         
     | 
| 
       135 
144 
     | 
    
         
             
                  end
         
     | 
| 
       136 
145 
     | 
    
         
             
                end
         
     |