rubocop 1.78.0 → 1.81.6
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 -3
 - data/config/default.yml +46 -21
 - data/exe/rubocop +1 -8
 - data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
 - data/lib/rubocop/cli.rb +6 -2
 - data/lib/rubocop/config_loader.rb +3 -1
 - data/lib/rubocop/config_store.rb +5 -0
 - data/lib/rubocop/cop/autocorrect_logic.rb +4 -4
 - 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/internal_affairs/node_pattern_groups.rb +3 -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/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_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 +0 -5
 - data/lib/rubocop/cop/layout/line_length.rb +9 -1
 - 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/trailing_whitespace.rb +1 -1
 - 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/deprecated_open_ssl_constant.rb +4 -1
 - data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
 - data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
 - data/lib/rubocop/cop/lint/literal_as_condition.rb +12 -0
 - data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -2
 - data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
 - data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
 - 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/self_assignment.rb +6 -5
 - data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
 - data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
 - data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
 - 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/check_line_breakable.rb +1 -1
 - data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
 - data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
 - data/lib/rubocop/cop/naming/method_name.rb +40 -1
 - data/lib/rubocop/cop/naming/predicate_method.rb +19 -3
 - data/lib/rubocop/cop/security/json_load.rb +33 -11
 - 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/conditional_assignment.rb +8 -4
 - 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/endless_method.rb +15 -2
 - data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
 - data/lib/rubocop/cop/style/exponential_notation.rb +1 -0
 - data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
 - 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 +2 -0
 - 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 +2 -4
 - 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_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_format.rb +26 -5
 - data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
 - data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_parentheses.rb +29 -11
 - 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/safe_navigation.rb +20 -1
 - data/lib/rubocop/cop/style/semicolon.rb +20 -5
 - data/lib/rubocop/cop/style/single_line_methods.rb +3 -3
 - data/lib/rubocop/cop/style/sole_nested_conditional.rb +30 -1
 - 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/trailing_comma_in_arguments.rb +45 -0
 - 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/markdown_formatter.rb +1 -0
 - data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
 - data/lib/rubocop/lsp/diagnostic.rb +21 -20
 - 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/result_cache.rb +14 -12
 - data/lib/rubocop/runner.rb +6 -4
 - 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 +3 -0
 - data/lib/ruby_lsp/rubocop/addon.rb +23 -8
 - data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
 - metadata +9 -6
 
| 
         @@ -3,33 +3,90 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            module RuboCop
         
     | 
| 
       4 
4 
     | 
    
         
             
              module Cop
         
     | 
| 
       5 
5 
     | 
    
         
             
                module Style
         
     | 
| 
       6 
     | 
    
         
            -
                  # Checks for  
     | 
| 
      
 6 
     | 
    
         
            +
                  # Checks for local variables and method parameters named `it`,
         
     | 
| 
       7 
7 
     | 
    
         
             
                  # where `it` can refer to the first anonymous parameter as of Ruby 3.4.
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # Use a meaningful variable name instead.
         
     | 
| 
       8 
9 
     | 
    
         
             
                  #
         
     | 
| 
       9 
     | 
    
         
            -
                  # Although Ruby allows reassigning `it` in these cases, it could
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # NOTE: Although Ruby allows reassigning `it` in these cases, it could
         
     | 
| 
       10 
11 
     | 
    
         
             
                  # cause confusion if `it` is used as a block parameter elsewhere.
         
     | 
| 
       11 
     | 
    
         
            -
                  # For consistency, this also applies to numblocks and blocks with
         
     | 
| 
       12 
     | 
    
         
            -
                  # parameters, even though `it` cannot be used in those cases.
         
     | 
| 
       13 
12 
     | 
    
         
             
                  #
         
     | 
| 
       14 
13 
     | 
    
         
             
                  # @example
         
     | 
| 
       15 
14 
     | 
    
         
             
                  #   # bad
         
     | 
| 
       16 
     | 
    
         
            -
                  #    
     | 
| 
       17 
     | 
    
         
            -
                  #   foo { |bar| it = bar }
         
     | 
| 
       18 
     | 
    
         
            -
                  #   foo { it = _2 }
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #   it = 5
         
     | 
| 
       19 
16 
     | 
    
         
             
                  #
         
     | 
| 
       20 
     | 
    
         
            -
                  #   # good 
     | 
| 
       21 
     | 
    
         
            -
                  #    
     | 
| 
       22 
     | 
    
         
            -
                  # 
     | 
| 
       23 
     | 
    
         
            -
                  #    
     | 
| 
      
 17 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #   var = 5
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 21 
     | 
    
         
            +
                  #   def foo(it)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 25 
     | 
    
         
            +
                  #   def foo(arg)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 27 
     | 
    
         
            +
                  #
         
     | 
| 
      
 28 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 29 
     | 
    
         
            +
                  #   def foo(it = 5)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 31 
     | 
    
         
            +
                  #
         
     | 
| 
      
 32 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 33 
     | 
    
         
            +
                  #   def foo(arg = 5)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  #
         
     | 
| 
      
 36 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 37 
     | 
    
         
            +
                  #   def foo(*it)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 39 
     | 
    
         
            +
                  #
         
     | 
| 
      
 40 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 41 
     | 
    
         
            +
                  #   def foo(*args)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  #
         
     | 
| 
      
 44 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 45 
     | 
    
         
            +
                  #   def foo(it:)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 47 
     | 
    
         
            +
                  #
         
     | 
| 
      
 48 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 49 
     | 
    
         
            +
                  #   def foo(arg:)
         
     | 
| 
      
 50 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 51 
     | 
    
         
            +
                  #
         
     | 
| 
      
 52 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 53 
     | 
    
         
            +
                  #   def foo(it: 5)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  #
         
     | 
| 
      
 56 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 57 
     | 
    
         
            +
                  #   def foo(arg: 5)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #
         
     | 
| 
      
 60 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 61 
     | 
    
         
            +
                  #   def foo(**it)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 63 
     | 
    
         
            +
                  #
         
     | 
| 
      
 64 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 65 
     | 
    
         
            +
                  #   def foo(**kwargs)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 67 
     | 
    
         
            +
                  #
         
     | 
| 
      
 68 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 69 
     | 
    
         
            +
                  #   def foo(&it)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  #
         
     | 
| 
      
 72 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 73 
     | 
    
         
            +
                  #   def foo(&block)
         
     | 
| 
      
 74 
     | 
    
         
            +
                  #   end
         
     | 
| 
       24 
75 
     | 
    
         
             
                  class ItAssignment < Base
         
     | 
| 
       25 
76 
     | 
    
         
             
                    MSG = '`it` is the default block parameter; consider another name.'
         
     | 
| 
       26 
77 
     | 
    
         | 
| 
       27 
78 
     | 
    
         
             
                    def on_lvasgn(node)
         
     | 
| 
       28 
79 
     | 
    
         
             
                      return unless node.name == :it
         
     | 
| 
       29 
     | 
    
         
            -
                      return unless node.each_ancestor(:any_block).any?
         
     | 
| 
       30 
80 
     | 
    
         | 
| 
       31 
81 
     | 
    
         
             
                      add_offense(node.loc.name)
         
     | 
| 
       32 
82 
     | 
    
         
             
                    end
         
     | 
| 
      
 83 
     | 
    
         
            +
                    alias on_arg on_lvasgn
         
     | 
| 
      
 84 
     | 
    
         
            +
                    alias on_optarg on_lvasgn
         
     | 
| 
      
 85 
     | 
    
         
            +
                    alias on_restarg on_lvasgn
         
     | 
| 
      
 86 
     | 
    
         
            +
                    alias on_blockarg on_lvasgn
         
     | 
| 
      
 87 
     | 
    
         
            +
                    alias on_kwarg on_lvasgn
         
     | 
| 
      
 88 
     | 
    
         
            +
                    alias on_kwoptarg on_lvasgn
         
     | 
| 
      
 89 
     | 
    
         
            +
                    alias on_kwrestarg on_lvasgn
         
     | 
| 
       33 
90 
     | 
    
         
             
                  end
         
     | 
| 
       34 
91 
     | 
    
         
             
                end
         
     | 
| 
       35 
92 
     | 
    
         
             
              end
         
     | 
| 
         @@ -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
         
     | 
| 
         @@ -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)
         
     | 
| 
         @@ -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 
     | 
    
         | 
| 
         @@ -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
         
     | 
| 
         @@ -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 
     | 
    
         | 
| 
         @@ -24,9 +24,6 @@ module RuboCop 
     | 
|
| 
       24 
24 
     | 
    
         
             
                      (send `{(send _recv _msg) str array hash const #variable?} :[] ...)
         
     | 
| 
       25 
25 
     | 
    
         
             
                    PATTERN
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
                    # @!method method_node_and_args(node)
         
     | 
| 
       28 
     | 
    
         
            -
                    def_node_matcher :method_node_and_args, '$(call _recv _msg $...)'
         
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
27 
     | 
    
         
             
                    # @!method rescue?(node)
         
     | 
| 
       31 
28 
     | 
    
         
             
                    def_node_matcher :rescue?, '{^resbody ^^resbody}'
         
     | 
| 
       32 
29 
     | 
    
         | 
| 
         @@ -149,7 +146,7 @@ module RuboCop 
     | 
|
| 
       149 
146 
     | 
    
         
             
                        return offense(begin_node, message)
         
     | 
| 
       150 
147 
     | 
    
         
             
                      end
         
     | 
| 
       151 
148 
     | 
    
         | 
| 
       152 
     | 
    
         
            -
                      check_send(begin_node, node) if node 
     | 
| 
      
 149 
     | 
    
         
            +
                      check_send(begin_node, node) if call_node?(node)
         
     | 
| 
       153 
150 
     | 
    
         
             
                    end
         
     | 
| 
       154 
151 
     | 
    
         | 
| 
       155 
152 
     | 
    
         
             
                    # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
         
     | 
| 
         @@ -169,6 +166,7 @@ module RuboCop 
     | 
|
| 
       169 
166 
     | 
    
         
             
                      end
         
     | 
| 
       170 
167 
     | 
    
         
             
                      return 'an interpolated expression' if interpolation?(begin_node)
         
     | 
| 
       171 
168 
     | 
    
         
             
                      return 'a method argument' if argument_of_parenthesized_method_call?(begin_node, node)
         
     | 
| 
      
 169 
     | 
    
         
            +
                      return 'a one-line rescue' if oneline_rescue_parentheses_required?(begin_node, node)
         
     | 
| 
       172 
170 
     | 
    
         | 
| 
       173 
171 
     | 
    
         
             
                      return if begin_node.chained?
         
     | 
| 
       174 
172 
     | 
    
         | 
| 
         @@ -200,6 +198,15 @@ module RuboCop 
     | 
|
| 
       200 
198 
     | 
    
         
             
                      parent.call_type? && parent.parenthesized? && parent.receiver != begin_node
         
     | 
| 
       201 
199 
     | 
    
         
             
                    end
         
     | 
| 
       202 
200 
     | 
    
         | 
| 
      
 201 
     | 
    
         
            +
                    def oneline_rescue_parentheses_required?(begin_node, node)
         
     | 
| 
      
 202 
     | 
    
         
            +
                      return false unless node.rescue_type?
         
     | 
| 
      
 203 
     | 
    
         
            +
                      return false unless (parent = begin_node.parent)
         
     | 
| 
      
 204 
     | 
    
         
            +
                      return false if parent.if_type? && parent.ternary?
         
     | 
| 
      
 205 
     | 
    
         
            +
                      return false if parent.conditional? && parent.condition == begin_node
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
                      !parent.type?(:call, :array, :pair)
         
     | 
| 
      
 208 
     | 
    
         
            +
                    end
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
       203 
210 
     | 
    
         
             
                    def method_call_parentheses_required?(node)
         
     | 
| 
       204 
211 
     | 
    
         
             
                      return false unless node.call_type?
         
     | 
| 
       205 
212 
     | 
    
         | 
| 
         @@ -210,10 +217,16 @@ module RuboCop 
     | 
|
| 
       210 
217 
     | 
    
         
             
                      !!config.for_enabled_cop('Style/ParenthesesAroundCondition')['AllowInMultilineConditions']
         
     | 
| 
       211 
218 
     | 
    
         
             
                    end
         
     | 
| 
       212 
219 
     | 
    
         | 
| 
      
 220 
     | 
    
         
            +
                    def call_node?(node)
         
     | 
| 
      
 221 
     | 
    
         
            +
                      node.call_type? || (node.any_block_type? && node.braces? && !node.lambda_or_proc?)
         
     | 
| 
      
 222 
     | 
    
         
            +
                    end
         
     | 
| 
      
 223 
     | 
    
         
            +
             
     | 
| 
       213 
224 
     | 
    
         
             
                    def check_send(begin_node, node)
         
     | 
| 
      
 225 
     | 
    
         
            +
                      node = node.send_node if node.any_block_type?
         
     | 
| 
      
 226 
     | 
    
         
            +
             
     | 
| 
       214 
227 
     | 
    
         
             
                      return check_unary(begin_node, node) if node.unary_operation?
         
     | 
| 
       215 
228 
     | 
    
         | 
| 
       216 
     | 
    
         
            -
                      return unless method_call_with_redundant_parentheses?(node)
         
     | 
| 
      
 229 
     | 
    
         
            +
                      return unless method_call_with_redundant_parentheses?(begin_node, node)
         
     | 
| 
       217 
230 
     | 
    
         
             
                      return if call_chain_starts_with_int?(begin_node, node) ||
         
     | 
| 
       218 
231 
     | 
    
         
             
                                do_end_block_in_method_chain?(begin_node, node)
         
     | 
| 
       219 
232 
     | 
    
         | 
| 
         @@ -224,8 +237,7 @@ module RuboCop 
     | 
|
| 
       224 
237 
     | 
    
         
             
                      return if begin_node.chained?
         
     | 
| 
       225 
238 
     | 
    
         | 
| 
       226 
239 
     | 
    
         
             
                      node = node.children.first while suspect_unary?(node)
         
     | 
| 
       227 
     | 
    
         
            -
             
     | 
| 
       228 
     | 
    
         
            -
                      return if node.send_type? && !method_call_with_redundant_parentheses?(node)
         
     | 
| 
      
 240 
     | 
    
         
            +
                      return unless method_call_with_redundant_parentheses?(begin_node, node)
         
     | 
| 
       229 
241 
     | 
    
         | 
| 
       230 
242 
     | 
    
         
             
                      offense(begin_node, 'a unary operation')
         
     | 
| 
       231 
243 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -287,13 +299,19 @@ module RuboCop 
     | 
|
| 
       287 
299 
     | 
    
         
             
                      end
         
     | 
| 
       288 
300 
     | 
    
         
             
                    end
         
     | 
| 
       289 
301 
     | 
    
         | 
| 
       290 
     | 
    
         
            -
                    def method_call_with_redundant_parentheses?(node)
         
     | 
| 
       291 
     | 
    
         
            -
                      return false unless node. 
     | 
| 
      
 302 
     | 
    
         
            +
                    def method_call_with_redundant_parentheses?(begin_node, node)
         
     | 
| 
      
 303 
     | 
    
         
            +
                      return false unless node.type?(:call, :super, :yield, :defined?)
         
     | 
| 
       292 
304 
     | 
    
         
             
                      return false if node.prefix_not?
         
     | 
| 
      
 305 
     | 
    
         
            +
                      return true if singular_parenthesized_parent?(begin_node)
         
     | 
| 
      
 306 
     | 
    
         
            +
             
     | 
| 
      
 307 
     | 
    
         
            +
                      node.arguments.empty? || parentheses?(node) || square_brackets?(node)
         
     | 
| 
      
 308 
     | 
    
         
            +
                    end
         
     | 
| 
       293 
309 
     | 
    
         | 
| 
       294 
     | 
    
         
            -
             
     | 
| 
      
 310 
     | 
    
         
            +
                    def singular_parenthesized_parent?(begin_node)
         
     | 
| 
      
 311 
     | 
    
         
            +
                      return true unless begin_node.parent
         
     | 
| 
      
 312 
     | 
    
         
            +
                      return false if begin_node.parent.type?(:splat, :kwsplat)
         
     | 
| 
       295 
313 
     | 
    
         | 
| 
       296 
     | 
    
         
            -
                       
     | 
| 
      
 314 
     | 
    
         
            +
                      parentheses?(begin_node) && begin_node.parent.children.one?
         
     | 
| 
       297 
315 
     | 
    
         
             
                    end
         
     | 
| 
       298 
316 
     | 
    
         | 
| 
       299 
317 
     | 
    
         
             
                    def only_begin_arg?(args)
         
     | 
| 
         @@ -66,6 +66,7 @@ module RuboCop 
     | 
|
| 
       66 
66 
     | 
    
         
             
                      DETERMINISTIC_REGEX.match?(regexp_node.source)
         
     | 
| 
       67 
67 
     | 
    
         
             
                    end
         
     | 
| 
       68 
68 
     | 
    
         | 
| 
      
 69 
     | 
    
         
            +
                    # rubocop:disable Metrics/MethodLength
         
     | 
| 
       69 
70 
     | 
    
         
             
                    def preferred_argument(regexp_node)
         
     | 
| 
       70 
71 
     | 
    
         
             
                      new_argument = replacement(regexp_node)
         
     | 
| 
       71 
72 
     | 
    
         | 
| 
         @@ -73,6 +74,8 @@ module RuboCop 
     | 
|
| 
       73 
74 
     | 
    
         
             
                        new_argument.gsub!("'", "\\\\'")
         
     | 
| 
       74 
75 
     | 
    
         
             
                        new_argument.gsub!('\"', '"')
         
     | 
| 
       75 
76 
     | 
    
         
             
                        quote = "'"
         
     | 
| 
      
 77 
     | 
    
         
            +
                      elsif new_argument.include?("\\'")
         
     | 
| 
      
 78 
     | 
    
         
            +
                        quote = "'"
         
     | 
| 
       76 
79 
     | 
    
         
             
                      elsif new_argument.include?('\'')
         
     | 
| 
       77 
80 
     | 
    
         
             
                        new_argument.gsub!("'", "\\\\'")
         
     | 
| 
       78 
81 
     | 
    
         
             
                        quote = "'"
         
     | 
| 
         @@ -84,6 +87,7 @@ module RuboCop 
     | 
|
| 
       84 
87 
     | 
    
         | 
| 
       85 
88 
     | 
    
         
             
                      "#{quote}#{new_argument}#{quote}"
         
     | 
| 
       86 
89 
     | 
    
         
             
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
                    # rubocop:enable Metrics/MethodLength
         
     | 
| 
       87 
91 
     | 
    
         | 
| 
       88 
92 
     | 
    
         
             
                    def replacement(regexp_node)
         
     | 
| 
       89 
93 
     | 
    
         
             
                      regexp_content = regexp_node.content
         
     |