rubocop 1.69.1 → 1.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/LICENSE.txt +1 -1
 - data/README.md +2 -2
 - data/config/default.yml +19 -2
 - data/lib/rubocop/cli/command/execute_runner.rb +3 -3
 - data/lib/rubocop/config.rb +13 -4
 - data/lib/rubocop/config_loader.rb +4 -0
 - data/lib/rubocop/config_loader_resolver.rb +14 -3
 - data/lib/rubocop/config_validator.rb +18 -8
 - data/lib/rubocop/cop/autocorrect_logic.rb +31 -34
 - data/lib/rubocop/cop/base.rb +6 -0
 - data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
 - data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
 - data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
 - data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
 - data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +4 -2
 - data/lib/rubocop/cop/internal_affairs.rb +1 -0
 - data/lib/rubocop/cop/layout/argument_alignment.rb +1 -7
 - data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
 - data/lib/rubocop/cop/layout/empty_lines_around_begin_body.rb +5 -6
 - data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
 - data/lib/rubocop/cop/layout/first_argument_indentation.rb +2 -7
 - data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
 - data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -6
 - data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
 - data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -0
 - data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +11 -2
 - data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
 - data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +1 -1
 - data/lib/rubocop/cop/layout/line_length.rb +1 -0
 - data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +24 -0
 - data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
 - data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
 - data/lib/rubocop/cop/layout/space_around_operators.rb +3 -3
 - data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
 - data/lib/rubocop/cop/lint/constant_reassignment.rb +152 -0
 - data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
 - data/lib/rubocop/cop/lint/literal_in_interpolation.rb +11 -3
 - data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
 - data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -2
 - data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +6 -14
 - data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
 - data/lib/rubocop/cop/lint/syntax.rb +4 -1
 - data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
 - data/lib/rubocop/cop/lint/void.rb +3 -2
 - data/lib/rubocop/cop/metrics/class_length.rb +9 -9
 - data/lib/rubocop/cop/metrics/method_length.rb +8 -1
 - data/lib/rubocop/cop/mixin/check_line_breakable.rb +7 -7
 - data/lib/rubocop/cop/mixin/comments_help.rb +6 -1
 - data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
 - data/lib/rubocop/cop/mixin/line_length_help.rb +5 -4
 - data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +46 -22
 - data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
 - data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
 - data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
 - data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
 - data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
 - data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -1
 - data/lib/rubocop/cop/style/and_or.rb +1 -1
 - data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -4
 - data/lib/rubocop/cop/style/block_delimiters.rb +8 -1
 - data/lib/rubocop/cop/style/class_and_module_children.rb +5 -2
 - data/lib/rubocop/cop/style/each_for_simple_loop.rb +3 -6
 - data/lib/rubocop/cop/style/empty_else.rb +4 -2
 - data/lib/rubocop/cop/style/empty_literal.rb +1 -1
 - data/lib/rubocop/cop/style/empty_method.rb +1 -1
 - data/lib/rubocop/cop/style/exact_regexp_match.rb +1 -2
 - data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
 - data/lib/rubocop/cop/style/file_null.rb +20 -4
 - data/lib/rubocop/cop/style/float_division.rb +8 -4
 - data/lib/rubocop/cop/style/hash_except.rb +54 -67
 - data/lib/rubocop/cop/style/hash_syntax.rb +5 -2
 - data/lib/rubocop/cop/style/if_with_semicolon.rb +6 -4
 - data/lib/rubocop/cop/style/it_assignment.rb +36 -0
 - data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +11 -1
 - data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
 - data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +1 -1
 - data/lib/rubocop/cop/style/missing_else.rb +2 -0
 - data/lib/rubocop/cop/style/multiple_comparison.rb +34 -22
 - data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
 - data/lib/rubocop/cop/style/object_then.rb +13 -15
 - data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
 - data/lib/rubocop/cop/style/raise_args.rb +5 -3
 - data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
 - data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
 - data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
 - data/lib/rubocop/cop/style/redundant_line_continuation.rb +12 -9
 - data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -4
 - data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
 - data/lib/rubocop/cop/style/redundant_self_assignment.rb +6 -5
 - data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
 - data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
 - data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
 - data/lib/rubocop/cop/style/single_line_methods.rb +2 -3
 - data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
 - data/lib/rubocop/cop/style/super_arguments.rb +63 -15
 - data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
 - data/lib/rubocop/cop/style/yoda_expression.rb +1 -0
 - data/lib/rubocop/cop/util.rb +9 -2
 - data/lib/rubocop/formatter/formatter_set.rb +1 -1
 - data/lib/rubocop/lsp/diagnostic.rb +189 -0
 - data/lib/rubocop/lsp/logger.rb +2 -2
 - data/lib/rubocop/lsp/routes.rb +7 -23
 - data/lib/rubocop/lsp/runtime.rb +15 -49
 - data/lib/rubocop/lsp/stdin_runner.rb +83 -0
 - data/lib/rubocop/magic_comment.rb +3 -3
 - data/lib/rubocop/path_util.rb +11 -8
 - data/lib/rubocop/rspec/shared_contexts.rb +4 -1
 - data/lib/rubocop/runner.rb +5 -6
 - data/lib/rubocop/target_ruby.rb +15 -0
 - data/lib/rubocop/version.rb +1 -1
 - data/lib/rubocop.rb +3 -0
 - data/lib/ruby_lsp/rubocop/addon.rb +78 -0
 - data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +50 -0
 - metadata +16 -8
 
| 
         @@ -73,7 +73,7 @@ module RuboCop 
     | 
|
| 
       73 
73 
     | 
    
         
             
                    LINE_CONTINUATION_PATTERN = /(\\\n)/.freeze
         
     | 
| 
       74 
74 
     | 
    
         
             
                    ALLOWED_STRING_TOKENS = %i[tSTRING tSTRING_CONTENT].freeze
         
     | 
| 
       75 
75 
     | 
    
         
             
                    ARGUMENT_TYPES = %i[
         
     | 
| 
       76 
     | 
    
         
            -
                      kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
         
     | 
| 
      
 76 
     | 
    
         
            +
                      kDEF kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
         
     | 
| 
       77 
77 
     | 
    
         
             
                      tLBRACK tLCURLY tLPAREN_ARG tSTRING tSTRING_BEG tSYMBOL tXSTRING_BEG
         
     | 
| 
       78 
78 
     | 
    
         
             
                    ].freeze
         
     | 
| 
       79 
79 
     | 
    
         
             
                    ARGUMENT_TAKING_FLOW_TOKEN_TYPES = %i[tIDENTIFIER kRETURN kBREAK kNEXT kYIELD].freeze
         
     | 
| 
         @@ -112,10 +112,13 @@ module RuboCop 
     | 
|
| 
       112 
112 
     | 
    
         
             
                    end
         
     | 
| 
       113 
113 
     | 
    
         | 
| 
       114 
114 
     | 
    
         
             
                    def inside_string_literal_or_method_with_argument?(range)
         
     | 
| 
      
 115 
     | 
    
         
            +
                      line_range = range_by_whole_lines(range)
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
       115 
117 
     | 
    
         
             
                      processed_source.tokens.each_cons(2).any? do |token, next_token|
         
     | 
| 
       116 
118 
     | 
    
         
             
                        next if token.line == next_token.line
         
     | 
| 
       117 
119 
     | 
    
         | 
| 
       118 
     | 
    
         
            -
                        inside_string_literal?(range, token) || 
     | 
| 
      
 120 
     | 
    
         
            +
                        inside_string_literal?(range, token) ||
         
     | 
| 
      
 121 
     | 
    
         
            +
                          method_with_argument?(line_range, token, next_token)
         
     | 
| 
       119 
122 
     | 
    
         
             
                      end
         
     | 
| 
       120 
123 
     | 
    
         
             
                    end
         
     | 
| 
       121 
124 
     | 
    
         | 
| 
         @@ -129,11 +132,10 @@ module RuboCop 
     | 
|
| 
       129 
132 
     | 
    
         
             
                      return true unless (node = find_node_for_line(range.last_line))
         
     | 
| 
       130 
133 
     | 
    
         
             
                      return false if argument_newline?(node)
         
     | 
| 
       131 
134 
     | 
    
         | 
| 
       132 
     | 
    
         
            -
                      source  
     | 
| 
       133 
     | 
    
         
            -
                       
     | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
       135 
     | 
    
         
            -
                       
     | 
| 
       136 
     | 
    
         
            -
                      parse(source.gsub("\\\n", "\n")).valid_syntax?
         
     | 
| 
      
 135 
     | 
    
         
            +
                      # Check if source is still valid without the continuation
         
     | 
| 
      
 136 
     | 
    
         
            +
                      source = processed_source.raw_source.dup
         
     | 
| 
      
 137 
     | 
    
         
            +
                      source[range.begin_pos, range.length] = "\n"
         
     | 
| 
      
 138 
     | 
    
         
            +
                      parse(source).valid_syntax?
         
     | 
| 
       137 
139 
     | 
    
         
             
                    end
         
     | 
| 
       138 
140 
     | 
    
         | 
| 
       139 
141 
     | 
    
         
             
                    def inspect_end_of_ruby_code_line_continuation
         
     | 
| 
         @@ -156,8 +158,9 @@ module RuboCop 
     | 
|
| 
       156 
158 
     | 
    
         
             
                    #
         
     | 
| 
       157 
159 
     | 
    
         
             
                    #   do_something \
         
     | 
| 
       158 
160 
     | 
    
         
             
                    #     argument
         
     | 
| 
       159 
     | 
    
         
            -
                    def method_with_argument?(current_token, next_token)
         
     | 
| 
      
 161 
     | 
    
         
            +
                    def method_with_argument?(line_range, current_token, next_token)
         
     | 
| 
       160 
162 
     | 
    
         
             
                      return false unless ARGUMENT_TAKING_FLOW_TOKEN_TYPES.include?(current_token.type)
         
     | 
| 
      
 163 
     | 
    
         
            +
                      return false unless current_token.pos.overlaps?(line_range)
         
     | 
| 
       161 
164 
     | 
    
         | 
| 
       162 
165 
     | 
    
         
             
                      ARGUMENT_TYPES.include?(next_token.type)
         
     | 
| 
       163 
166 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -181,7 +184,7 @@ module RuboCop 
     | 
|
| 
       181 
184 
     | 
    
         | 
| 
       182 
185 
     | 
    
         
             
                    def find_node_for_line(last_line)
         
     | 
| 
       183 
186 
     | 
    
         
             
                      processed_source.ast.each_node do |node|
         
     | 
| 
       184 
     | 
    
         
            -
                        return node if  
     | 
| 
      
 187 
     | 
    
         
            +
                        return node if same_line?(node, last_line)
         
     | 
| 
       185 
188 
     | 
    
         
             
                      end
         
     | 
| 
       186 
189 
     | 
    
         
             
                    end
         
     | 
| 
       187 
190 
     | 
    
         | 
| 
         @@ -166,10 +166,7 @@ module RuboCop 
     | 
|
| 
       166 
166 
     | 
    
         
             
                    def_node_matcher :interpolation?, '[^begin ^^dstr]'
         
     | 
| 
       167 
167 
     | 
    
         | 
| 
       168 
168 
     | 
    
         
             
                    def allow_in_multiline_conditions?
         
     | 
| 
       169 
     | 
    
         
            -
                       
     | 
| 
       170 
     | 
    
         
            -
                      return false unless parentheses_around_condition_config['Enabled']
         
     | 
| 
       171 
     | 
    
         
            -
             
     | 
| 
       172 
     | 
    
         
            -
                      !!parentheses_around_condition_config['AllowInMultilineConditions']
         
     | 
| 
      
 169 
     | 
    
         
            +
                      !!config.for_enabled_cop('Style/ParenthesesAroundCondition')['AllowInMultilineConditions']
         
     | 
| 
       173 
170 
     | 
    
         
             
                    end
         
     | 
| 
       174 
171 
     | 
    
         | 
| 
       175 
172 
     | 
    
         
             
                    def check_send(begin_node, node)
         
     | 
| 
         @@ -52,7 +52,7 @@ module RuboCop 
     | 
|
| 
       52 
52 
     | 
    
         
             
                    # rubocop:disable Metrics/AbcSize
         
     | 
| 
       53 
53 
     | 
    
         
             
                    def on_lvasgn(node)
         
     | 
| 
       54 
54 
     | 
    
         
             
                      return unless (rhs = node.rhs)
         
     | 
| 
       55 
     | 
    
         
            -
                      return unless rhs. 
     | 
| 
      
 55 
     | 
    
         
            +
                      return unless rhs.call_type? && method_returning_self?(rhs.method_name)
         
     | 
| 
       56 
56 
     | 
    
         
             
                      return unless (receiver = rhs.receiver)
         
     | 
| 
       57 
57 
     | 
    
         | 
| 
       58 
58 
     | 
    
         
             
                      receiver_type = ASSIGNMENT_TYPE_TO_RECEIVER_TYPE[node.type]
         
     | 
| 
         @@ -77,6 +77,7 @@ module RuboCop 
     | 
|
| 
       77 
77 
     | 
    
         
             
                        corrector.remove(correction_range(node))
         
     | 
| 
       78 
78 
     | 
    
         
             
                      end
         
     | 
| 
       79 
79 
     | 
    
         
             
                    end
         
     | 
| 
      
 80 
     | 
    
         
            +
                    alias on_csend on_send
         
     | 
| 
       80 
81 
     | 
    
         | 
| 
       81 
82 
     | 
    
         
             
                    private
         
     | 
| 
       82 
83 
     | 
    
         | 
| 
         @@ -88,7 +89,7 @@ module RuboCop 
     | 
|
| 
       88 
89 
     | 
    
         
             
                    def_node_matcher :redundant_self_assignment?, <<~PATTERN
         
     | 
| 
       89 
90 
     | 
    
         
             
                      (send
         
     | 
| 
       90 
91 
     | 
    
         
             
                        (self) _
         
     | 
| 
       91 
     | 
    
         
            -
                        ( 
     | 
| 
      
 92 
     | 
    
         
            +
                        (call
         
     | 
| 
       92 
93 
     | 
    
         
             
                          (send
         
     | 
| 
       93 
94 
     | 
    
         
             
                            {(self) nil?} %1) #method_returning_self?
         
     | 
| 
       94 
95 
     | 
    
         
             
                          ...))
         
     | 
| 
         @@ -96,10 +97,10 @@ module RuboCop 
     | 
|
| 
       96 
97 
     | 
    
         | 
| 
       97 
98 
     | 
    
         
             
                    # @!method redundant_nonself_assignment?(node, receiver, method_name)
         
     | 
| 
       98 
99 
     | 
    
         
             
                    def_node_matcher :redundant_nonself_assignment?, <<~PATTERN
         
     | 
| 
       99 
     | 
    
         
            -
                      ( 
     | 
| 
      
 100 
     | 
    
         
            +
                      (call
         
     | 
| 
       100 
101 
     | 
    
         
             
                        %1 _
         
     | 
| 
       101 
     | 
    
         
            -
                        ( 
     | 
| 
       102 
     | 
    
         
            -
                          ( 
     | 
| 
      
 102 
     | 
    
         
            +
                        (call
         
     | 
| 
      
 103 
     | 
    
         
            +
                          (call
         
     | 
| 
       103 
104 
     | 
    
         
             
                            %1 %2) #method_returning_self?
         
     | 
| 
       104 
105 
     | 
    
         
             
                          ...))
         
     | 
| 
       105 
106 
     | 
    
         
             
                    PATTERN
         
     | 
| 
         @@ -323,7 +323,7 @@ module RuboCop 
     | 
|
| 
       323 
323 
     | 
    
         
             
                      return true if unsafe_method?(method)
         
     | 
| 
       324 
324 
     | 
    
         | 
| 
       325 
325 
     | 
    
         
             
                      method.each_ancestor(:send).any? do |ancestor|
         
     | 
| 
       326 
     | 
    
         
            -
                        break true unless config. 
     | 
| 
      
 326 
     | 
    
         
            +
                        break true unless config.cop_enabled?('Lint/SafeNavigationChain')
         
     | 
| 
       327 
327 
     | 
    
         | 
| 
       328 
328 
     | 
    
         
             
                        break true if unsafe_method?(ancestor)
         
     | 
| 
       329 
329 
     | 
    
         
             
                        break true if nil_methods.include?(ancestor.method_name)
         
     | 
| 
         @@ -68,7 +68,7 @@ module RuboCop 
     | 
|
| 
       68 
68 
     | 
    
         
             
                    def on_send(node)
         
     | 
| 
       69 
69 
     | 
    
         
             
                      return if allow_send? && !node.method?(:public_send)
         
     | 
| 
       70 
70 
     | 
    
         
             
                      return unless (first_argument = node.first_argument)
         
     | 
| 
       71 
     | 
    
         
            -
                      return unless  
     | 
| 
      
 71 
     | 
    
         
            +
                      return unless first_argument.type?(*STATIC_METHOD_NAME_NODE_TYPES)
         
     | 
| 
       72 
72 
     | 
    
         | 
| 
       73 
73 
     | 
    
         
             
                      offense_range = offense_range(node)
         
     | 
| 
       74 
74 
     | 
    
         
             
                      method_name = first_argument.value
         
     | 
| 
         @@ -83,6 +83,7 @@ module RuboCop 
     | 
|
| 
       83 
83 
     | 
    
         
             
                        end
         
     | 
| 
       84 
84 
     | 
    
         
             
                      end
         
     | 
| 
       85 
85 
     | 
    
         
             
                    end
         
     | 
| 
      
 86 
     | 
    
         
            +
                    alias on_csend on_send
         
     | 
| 
       86 
87 
     | 
    
         
             
                    # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
         
     | 
| 
       87 
88 
     | 
    
         | 
| 
       88 
89 
     | 
    
         
             
                    private
         
     | 
| 
         @@ -68,8 +68,7 @@ module RuboCop 
     | 
|
| 
       68 
68 
     | 
    
         
             
                    end
         
     | 
| 
       69 
69 
     | 
    
         | 
| 
       70 
70 
     | 
    
         
             
                    def single_line_blocks_preferred?
         
     | 
| 
       71 
     | 
    
         
            -
                       
     | 
| 
       72 
     | 
    
         
            -
                      redundant_line_break_config['Enabled'] && redundant_line_break_config['InspectBlocks']
         
     | 
| 
      
 71 
     | 
    
         
            +
                      @config.for_enabled_cop('Layout/RedundantLineBreak')['InspectBlocks']
         
     | 
| 
       73 
72 
     | 
    
         
             
                    end
         
     | 
| 
       74 
73 
     | 
    
         
             
                  end
         
     | 
| 
       75 
74 
     | 
    
         
             
                end
         
     | 
| 
         @@ -134,10 +134,9 @@ module RuboCop 
     | 
|
| 
       134 
134 
     | 
    
         
             
                    end
         
     | 
| 
       135 
135 
     | 
    
         | 
| 
       136 
136 
     | 
    
         
             
                    def disallow_endless_method_style?
         
     | 
| 
       137 
     | 
    
         
            -
                       
     | 
| 
       138 
     | 
    
         
            -
                      return true unless endless_method_config['Enabled']
         
     | 
| 
      
 137 
     | 
    
         
            +
                      return true unless config.cop_enabled?('Style/EndlessMethod')
         
     | 
| 
       139 
138 
     | 
    
         | 
| 
       140 
     | 
    
         
            -
                       
     | 
| 
      
 139 
     | 
    
         
            +
                      config.for_cop('Style/EndlessMethod')['EnforcedStyle'] == 'disallow'
         
     | 
| 
       141 
140 
     | 
    
         
             
                    end
         
     | 
| 
       142 
141 
     | 
    
         
             
                  end
         
     | 
| 
       143 
142 
     | 
    
         
             
                end
         
     | 
| 
         @@ -78,38 +78,67 @@ module RuboCop 
     | 
|
| 
       78 
78 
     | 
    
         
             
                      return unless node.arguments.one?
         
     | 
| 
       79 
79 
     | 
    
         | 
| 
       80 
80 
     | 
    
         
             
                      range_node = node.first_argument
         
     | 
| 
       81 
     | 
    
         
            -
                       
     | 
| 
       82 
     | 
    
         
            -
                      unless (message, removal_range = 
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
      
 81 
     | 
    
         
            +
                      offense_range = find_offense_range(node)
         
     | 
| 
      
 82 
     | 
    
         
            +
                      return unless (message, removal_range =
         
     | 
| 
      
 83 
     | 
    
         
            +
                                       offense_message_with_removal_range(node, range_node, offense_range))
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                      # Changing the range to beginningless or endless when unparenthesized
         
     | 
| 
      
 86 
     | 
    
         
            +
                      # changes the semantics of the code, and thus will not be considered
         
     | 
| 
      
 87 
     | 
    
         
            +
                      # an offense.
         
     | 
| 
      
 88 
     | 
    
         
            +
                      return if removal_range != offense_range && unparenthesized_call?(node)
         
     | 
| 
       85 
89 
     | 
    
         | 
| 
       86 
     | 
    
         
            -
                      add_offense( 
     | 
| 
      
 90 
     | 
    
         
            +
                      add_offense(offense_range, message: message) do |corrector|
         
     | 
| 
       87 
91 
     | 
    
         
             
                        corrector.remove(removal_range)
         
     | 
| 
       88 
92 
     | 
    
         
             
                      end
         
     | 
| 
       89 
93 
     | 
    
         
             
                    end
         
     | 
| 
      
 94 
     | 
    
         
            +
                    alias on_csend on_send
         
     | 
| 
       90 
95 
     | 
    
         | 
| 
       91 
96 
     | 
    
         
             
                    private
         
     | 
| 
       92 
97 
     | 
    
         | 
| 
       93 
     | 
    
         
            -
                    def  
     | 
| 
      
 98 
     | 
    
         
            +
                    def unparenthesized_call?(node)
         
     | 
| 
      
 99 
     | 
    
         
            +
                      node.loc.dot && !node.parenthesized?
         
     | 
| 
      
 100 
     | 
    
         
            +
                    end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                    def find_offense_range(node)
         
     | 
| 
      
 103 
     | 
    
         
            +
                      if node.loc.dot
         
     | 
| 
      
 104 
     | 
    
         
            +
                        node.loc.dot.join(node.source_range.end)
         
     | 
| 
      
 105 
     | 
    
         
            +
                      else
         
     | 
| 
      
 106 
     | 
    
         
            +
                        node.loc.selector
         
     | 
| 
      
 107 
     | 
    
         
            +
                      end
         
     | 
| 
      
 108 
     | 
    
         
            +
                    end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                    def offense_message_with_removal_range(node, range_node, offense_range)
         
     | 
| 
       94 
111 
     | 
    
         
             
                      if range_from_zero_till_minus_one?(range_node)
         
     | 
| 
       95 
     | 
    
         
            -
                        [format(MSG_USELESS_RANGE, prefer:  
     | 
| 
      
 112 
     | 
    
         
            +
                        [format(MSG_USELESS_RANGE, prefer: offense_range.source), offense_range]
         
     | 
| 
       96 
113 
     | 
    
         
             
                      elsif range_till_minus_one?(range_node)
         
     | 
| 
       97 
114 
     | 
    
         
             
                        [
         
     | 
| 
       98 
     | 
    
         
            -
                           
     | 
| 
      
 115 
     | 
    
         
            +
                          offense_message_for_partial_range(node, endless(range_node), offense_range),
         
     | 
| 
      
 116 
     | 
    
         
            +
                          range_node.end
         
     | 
| 
       99 
117 
     | 
    
         
             
                        ]
         
     | 
| 
       100 
118 
     | 
    
         
             
                      elsif range_from_zero?(range_node) && target_ruby_version >= 2.7
         
     | 
| 
       101 
119 
     | 
    
         
             
                        [
         
     | 
| 
       102 
     | 
    
         
            -
                           
     | 
| 
      
 120 
     | 
    
         
            +
                          offense_message_for_partial_range(node, beginless(range_node), offense_range),
         
     | 
| 
      
 121 
     | 
    
         
            +
                          range_node.begin
         
     | 
| 
       103 
122 
     | 
    
         
             
                        ]
         
     | 
| 
       104 
123 
     | 
    
         
             
                      end
         
     | 
| 
       105 
124 
     | 
    
         
             
                    end
         
     | 
| 
       106 
125 
     | 
    
         | 
| 
      
 126 
     | 
    
         
            +
                    def offense_message_for_partial_range(node, prefer, offense_range)
         
     | 
| 
      
 127 
     | 
    
         
            +
                      current = node.loc.dot ? arguments_source(node) : offense_range.source
         
     | 
| 
      
 128 
     | 
    
         
            +
                      prefer = "[#{prefer}]" unless node.loc.dot
         
     | 
| 
      
 129 
     | 
    
         
            +
                      format(MSG, prefer: prefer, current: current)
         
     | 
| 
      
 130 
     | 
    
         
            +
                    end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
       107 
132 
     | 
    
         
             
                    def endless(range_node)
         
     | 
| 
       108 
     | 
    
         
            -
                      " 
     | 
| 
      
 133 
     | 
    
         
            +
                      "#{range_node.begin.source}#{range_node.loc.operator.source}"
         
     | 
| 
       109 
134 
     | 
    
         
             
                    end
         
     | 
| 
       110 
135 
     | 
    
         | 
| 
       111 
136 
     | 
    
         
             
                    def beginless(range_node)
         
     | 
| 
       112 
     | 
    
         
            -
                      " 
     | 
| 
      
 137 
     | 
    
         
            +
                      "#{range_node.loc.operator.source}#{range_node.end.source}"
         
     | 
| 
      
 138 
     | 
    
         
            +
                    end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                    def arguments_source(node)
         
     | 
| 
      
 141 
     | 
    
         
            +
                      node.first_argument.source_range.join(node.last_argument.source_range.end).source
         
     | 
| 
       113 
142 
     | 
    
         
             
                    end
         
     | 
| 
       114 
143 
     | 
    
         
             
                  end
         
     | 
| 
       115 
144 
     | 
    
         
             
                end
         
     | 
| 
         @@ -23,6 +23,10 @@ module RuboCop 
     | 
|
| 
       23 
23 
     | 
    
         
             
                  # `define_method`, therefore, `super` used within these blocks will be allowed.
         
     | 
| 
       24 
24 
     | 
    
         
             
                  # This approach might result in false negatives, yet ensuring safe detection takes precedence.
         
     | 
| 
       25 
25 
     | 
    
         
             
                  #
         
     | 
| 
      
 26 
     | 
    
         
            +
                  # NOTE: When forwarding the same arguments but replacing the block argument with a new inline
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # block, it is not necessary to explicitly list the non-block arguments. As such, an offense
         
     | 
| 
      
 28 
     | 
    
         
            +
                  # will be registered in this case.
         
     | 
| 
      
 29 
     | 
    
         
            +
                  #
         
     | 
| 
       26 
30 
     | 
    
         
             
                  # @example
         
     | 
| 
       27 
31 
     | 
    
         
             
                  #   # bad
         
     | 
| 
       28 
32 
     | 
    
         
             
                  #   def method(*args, **kwargs)
         
     | 
| 
         @@ -44,6 +48,16 @@ module RuboCop 
     | 
|
| 
       44 
48 
     | 
    
         
             
                  #     super()
         
     | 
| 
       45 
49 
     | 
    
         
             
                  #   end
         
     | 
| 
       46 
50 
     | 
    
         
             
                  #
         
     | 
| 
      
 51 
     | 
    
         
            +
                  #   # bad - forwarding with overridden block
         
     | 
| 
      
 52 
     | 
    
         
            +
                  #   def method(*args, **kwargs, &block)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  #     super(*args, **kwargs) { do_something }
         
     | 
| 
      
 54 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  #
         
     | 
| 
      
 56 
     | 
    
         
            +
                  #   # good - implicitly passing all non-block arguments
         
     | 
| 
      
 57 
     | 
    
         
            +
                  #   def method(*args, **kwargs, &block)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  #     super { do_something }
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 60 
     | 
    
         
            +
                  #
         
     | 
| 
       47 
61 
     | 
    
         
             
                  #   # good - assigning to the block variable before calling super
         
     | 
| 
       48 
62 
     | 
    
         
             
                  #   def method(&block)
         
     | 
| 
       49 
63 
     | 
    
         
             
                  #     # Assigning to the block variable would pass the old value to super,
         
     | 
| 
         @@ -58,44 +72,75 @@ module RuboCop 
     | 
|
| 
       58 
72 
     | 
    
         
             
                    ASSIGN_TYPES = %i[or_asgn lvasgn].freeze
         
     | 
| 
       59 
73 
     | 
    
         | 
| 
       60 
74 
     | 
    
         
             
                    MSG = 'Call `super` without arguments and parentheses when the signature is identical.'
         
     | 
| 
      
 75 
     | 
    
         
            +
                    MSG_INLINE_BLOCK = 'Call `super` without arguments and parentheses when all positional ' \
         
     | 
| 
      
 76 
     | 
    
         
            +
                                       'and keyword arguments are forwarded.'
         
     | 
| 
       61 
77 
     | 
    
         | 
| 
       62 
78 
     | 
    
         
             
                    def on_super(super_node)
         
     | 
| 
       63 
     | 
    
         
            -
                      def_node = super_node 
     | 
| 
      
 79 
     | 
    
         
            +
                      return unless (def_node = find_def_node(super_node))
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                      def_node_args = def_node.arguments.argument_list
         
     | 
| 
      
 82 
     | 
    
         
            +
                      super_args = preprocess_super_args(super_node.arguments)
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                      return unless arguments_identical?(def_node, super_node, def_node_args, super_args)
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                      # If the number of arguments to the def node and super node are different here,
         
     | 
| 
      
 87 
     | 
    
         
            +
                      # it's because the block argument is not forwarded.
         
     | 
| 
      
 88 
     | 
    
         
            +
                      message = def_node_args.size == super_args.size ? MSG : MSG_INLINE_BLOCK
         
     | 
| 
      
 89 
     | 
    
         
            +
                      add_offense(super_node, message: message) do |corrector|
         
     | 
| 
      
 90 
     | 
    
         
            +
                        corrector.replace(super_node, 'super')
         
     | 
| 
      
 91 
     | 
    
         
            +
                      end
         
     | 
| 
      
 92 
     | 
    
         
            +
                    end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                    private
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                    def find_def_node(super_node)
         
     | 
| 
      
 97 
     | 
    
         
            +
                      super_node.ancestors.find do |node|
         
     | 
| 
       64 
98 
     | 
    
         
             
                        # When defining dynamic methods, implicitly calling `super` is not possible.
         
     | 
| 
       65 
99 
     | 
    
         
             
                        # Since there is a possibility of delegation to `define_method`,
         
     | 
| 
       66 
100 
     | 
    
         
             
                        # `super` used within the block is always allowed.
         
     | 
| 
       67 
     | 
    
         
            -
                        break if node.block_type?
         
     | 
| 
      
 101 
     | 
    
         
            +
                        break if node.block_type? && !block_sends_to_super?(super_node, node)
         
     | 
| 
       68 
102 
     | 
    
         | 
| 
       69 
103 
     | 
    
         
             
                        break node if DEF_TYPES.include?(node.type)
         
     | 
| 
       70 
104 
     | 
    
         
             
                      end
         
     | 
| 
       71 
     | 
    
         
            -
                      return unless def_node
         
     | 
| 
       72 
     | 
    
         
            -
                      return unless arguments_identical?(def_node, def_node.arguments.argument_list,
         
     | 
| 
       73 
     | 
    
         
            -
                                                         super_node.arguments)
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
                      add_offense(super_node) { |corrector| corrector.replace(super_node, 'super') }
         
     | 
| 
       76 
105 
     | 
    
         
             
                    end
         
     | 
| 
       77 
106 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
                    private
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
       80 
107 
     | 
    
         
             
                    # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
         
     | 
| 
       81 
     | 
    
         
            -
                    def arguments_identical?(def_node, def_args, super_args)
         
     | 
| 
       82 
     | 
    
         
            -
                       
     | 
| 
       83 
     | 
    
         
            -
                      return false if def_args.size != super_args.size
         
     | 
| 
      
 108 
     | 
    
         
            +
                    def arguments_identical?(def_node, super_node, def_args, super_args)
         
     | 
| 
      
 109 
     | 
    
         
            +
                      return false if argument_list_size_differs?(def_args, super_args, super_node)
         
     | 
| 
       84 
110 
     | 
    
         | 
| 
       85 
111 
     | 
    
         
             
                      def_args.zip(super_args).each do |def_arg, super_arg|
         
     | 
| 
       86 
112 
     | 
    
         
             
                        next if positional_arg_same?(def_arg, super_arg)
         
     | 
| 
       87 
113 
     | 
    
         
             
                        next if positional_rest_arg_same(def_arg, super_arg)
         
     | 
| 
       88 
114 
     | 
    
         
             
                        next if keyword_arg_same?(def_arg, super_arg)
         
     | 
| 
       89 
115 
     | 
    
         
             
                        next if keyword_rest_arg_same?(def_arg, super_arg)
         
     | 
| 
       90 
     | 
    
         
            -
                        next if block_arg_same?(def_node, def_arg, super_arg)
         
     | 
| 
      
 116 
     | 
    
         
            +
                        next if block_arg_same?(def_node, super_node, def_arg, super_arg)
         
     | 
| 
       91 
117 
     | 
    
         
             
                        next if forward_arg_same?(def_arg, super_arg)
         
     | 
| 
       92 
118 
     | 
    
         | 
| 
       93 
119 
     | 
    
         
             
                        return false
         
     | 
| 
       94 
120 
     | 
    
         
             
                      end
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
       95 
122 
     | 
    
         
             
                      true
         
     | 
| 
       96 
123 
     | 
    
         
             
                    end
         
     | 
| 
       97 
124 
     | 
    
         
             
                    # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
         
     | 
| 
       98 
125 
     | 
    
         | 
| 
      
 126 
     | 
    
         
            +
                    def argument_list_size_differs?(def_args, super_args, super_node)
         
     | 
| 
      
 127 
     | 
    
         
            +
                      # If the def node has a block argument and the super node has an explicit block,
         
     | 
| 
      
 128 
     | 
    
         
            +
                      # the number of arguments is the same, so ignore the def node block arg.
         
     | 
| 
      
 129 
     | 
    
         
            +
                      def_args_size = def_args.size
         
     | 
| 
      
 130 
     | 
    
         
            +
                      def_args_size -= 1 if def_args.any?(&:blockarg_type?) && block_sends_to_super?(super_node)
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                      def_args_size != super_args.size
         
     | 
| 
      
 133 
     | 
    
         
            +
                    end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                    def block_sends_to_super?(super_node, parent_node = super_node.parent)
         
     | 
| 
      
 136 
     | 
    
         
            +
                      # Checks if the send node of a block is the given super node,
         
     | 
| 
      
 137 
     | 
    
         
            +
                      # or a method chain containing it.
         
     | 
| 
      
 138 
     | 
    
         
            +
                      return false unless parent_node
         
     | 
| 
      
 139 
     | 
    
         
            +
                      return false unless parent_node.type?(:block, :numblock)
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                      parent_node.send_node.each_node(:super).any?(super_node)
         
     | 
| 
      
 142 
     | 
    
         
            +
                    end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
       99 
144 
     | 
    
         
             
                    def positional_arg_same?(def_arg, super_arg)
         
     | 
| 
       100 
145 
     | 
    
         
             
                      return false unless def_arg.arg_type? || def_arg.optarg_type?
         
     | 
| 
       101 
146 
     | 
    
         
             
                      return false unless super_arg.lvar_type?
         
     | 
| 
         @@ -133,8 +178,11 @@ module RuboCop 
     | 
|
| 
       133 
178 
     | 
    
         
             
                      def_arg.name == lvar_node.children.first
         
     | 
| 
       134 
179 
     | 
    
         
             
                    end
         
     | 
| 
       135 
180 
     | 
    
         | 
| 
       136 
     | 
    
         
            -
                    def block_arg_same?(def_node, def_arg, super_arg)
         
     | 
| 
       137 
     | 
    
         
            -
                      return false unless def_arg.blockarg_type? 
     | 
| 
      
 181 
     | 
    
         
            +
                    def block_arg_same?(def_node, super_node, def_arg, super_arg)
         
     | 
| 
      
 182 
     | 
    
         
            +
                      return false unless def_arg.blockarg_type?
         
     | 
| 
      
 183 
     | 
    
         
            +
                      return true if block_sends_to_super?(super_node)
         
     | 
| 
      
 184 
     | 
    
         
            +
                      return false unless super_arg.block_pass_type?
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
       138 
186 
     | 
    
         
             
                      # anonymous forwarding
         
     | 
| 
       139 
187 
     | 
    
         
             
                      return true if (block_pass_child = super_arg.children.first).nil? && def_arg.name.nil?
         
     | 
| 
       140 
188 
     | 
    
         | 
| 
         @@ -85,6 +85,12 @@ module RuboCop 
     | 
|
| 
       85 
85 
     | 
    
         
             
                    NONCOMMUTATIVE_OPERATORS = %i[===].freeze
         
     | 
| 
       86 
86 
     | 
    
         
             
                    PROGRAM_NAMES = %i[$0 $PROGRAM_NAME].freeze
         
     | 
| 
       87 
87 
     | 
    
         
             
                    RESTRICT_ON_SEND = RuboCop::AST::Node::COMPARISON_OPERATORS
         
     | 
| 
      
 88 
     | 
    
         
            +
                    ENFORCE_YODA_STYLES = %i[
         
     | 
| 
      
 89 
     | 
    
         
            +
                      require_for_all_comparison_operators require_for_equality_operators_only
         
     | 
| 
      
 90 
     | 
    
         
            +
                    ].freeze
         
     | 
| 
      
 91 
     | 
    
         
            +
                    EQUALITY_ONLY_STYLES = %i[
         
     | 
| 
      
 92 
     | 
    
         
            +
                      forbid_for_equality_operators_only require_for_equality_operators_only
         
     | 
| 
      
 93 
     | 
    
         
            +
                    ].freeze
         
     | 
| 
       88 
94 
     | 
    
         | 
| 
       89 
95 
     | 
    
         
             
                    # @!method file_constant_equal_program_name?(node)
         
     | 
| 
       90 
96 
     | 
    
         
             
                    def_node_matcher :file_constant_equal_program_name?, <<~PATTERN
         
     | 
| 
         @@ -105,13 +111,11 @@ module RuboCop 
     | 
|
| 
       105 
111 
     | 
    
         
             
                    private
         
     | 
| 
       106 
112 
     | 
    
         | 
| 
       107 
113 
     | 
    
         
             
                    def enforce_yoda?
         
     | 
| 
       108 
     | 
    
         
            -
                      style 
     | 
| 
       109 
     | 
    
         
            -
                        style == :require_for_equality_operators_only
         
     | 
| 
      
 114 
     | 
    
         
            +
                      ENFORCE_YODA_STYLES.include?(style)
         
     | 
| 
       110 
115 
     | 
    
         
             
                    end
         
     | 
| 
       111 
116 
     | 
    
         | 
| 
       112 
117 
     | 
    
         
             
                    def equality_only?
         
     | 
| 
       113 
     | 
    
         
            -
                      style 
     | 
| 
       114 
     | 
    
         
            -
                        style == :require_for_equality_operators_only
         
     | 
| 
      
 118 
     | 
    
         
            +
                      EQUALITY_ONLY_STYLES.include?(style)
         
     | 
| 
       115 
119 
     | 
    
         
             
                    end
         
     | 
| 
       116 
120 
     | 
    
         | 
| 
       117 
121 
     | 
    
         
             
                    def yoda_compatible_condition?(node)
         
     | 
    
        data/lib/rubocop/cop/util.rb
    CHANGED
    
    | 
         @@ -193,11 +193,18 @@ module RuboCop 
     | 
|
| 
       193 
193 
     | 
    
         
             
                      enforced_style.sub(/^Enforced/, 'Supported').sub('Style', 'Styles')
         
     | 
| 
       194 
194 
     | 
    
         
             
                  end
         
     | 
| 
       195 
195 
     | 
    
         | 
| 
      
 196 
     | 
    
         
            +
                  def parse_regexp(text)
         
     | 
| 
      
 197 
     | 
    
         
            +
                    Regexp::Parser.parse(text)
         
     | 
| 
      
 198 
     | 
    
         
            +
                  rescue Regexp::Parser::Error
         
     | 
| 
      
 199 
     | 
    
         
            +
                    # Upon encountering an invalid regular expression,
         
     | 
| 
      
 200 
     | 
    
         
            +
                    # we aim to proceed and identify any remaining potential offenses.
         
     | 
| 
      
 201 
     | 
    
         
            +
                    nil
         
     | 
| 
      
 202 
     | 
    
         
            +
                  end
         
     | 
| 
      
 203 
     | 
    
         
            +
             
     | 
| 
       196 
204 
     | 
    
         
             
                  private
         
     | 
| 
       197 
205 
     | 
    
         | 
| 
       198 
206 
     | 
    
         
             
                  def compatible_external_encoding_for?(src)
         
     | 
| 
       199 
     | 
    
         
            -
                    src 
     | 
| 
       200 
     | 
    
         
            -
                    src.force_encoding(Encoding.default_external).valid_encoding?
         
     | 
| 
      
 207 
     | 
    
         
            +
                    src.dup.force_encoding(Encoding.default_external).valid_encoding?
         
     | 
| 
       201 
208 
     | 
    
         
             
                  end
         
     | 
| 
       202 
209 
     | 
    
         | 
| 
       203 
210 
     | 
    
         
             
                  def include_or_equal?(source, target)
         
     | 
| 
         @@ -0,0 +1,189 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative 'severity'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
            # This code is based on https://github.com/standardrb/standard.
         
     | 
| 
      
 7 
     | 
    
         
            +
            #
         
     | 
| 
      
 8 
     | 
    
         
            +
            # Copyright (c) 2023 Test Double, Inc.
         
     | 
| 
      
 9 
     | 
    
         
            +
            #
         
     | 
| 
      
 10 
     | 
    
         
            +
            # The MIT License (MIT)
         
     | 
| 
      
 11 
     | 
    
         
            +
            #
         
     | 
| 
      
 12 
     | 
    
         
            +
            # https://github.com/standardrb/standard/blob/main/LICENSE.txt
         
     | 
| 
      
 13 
     | 
    
         
            +
            #
         
     | 
| 
      
 14 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 15 
     | 
    
         
            +
              module LSP
         
     | 
| 
      
 16 
     | 
    
         
            +
                # Diagnostic for Language Server Protocol of RuboCop.
         
     | 
| 
      
 17 
     | 
    
         
            +
                # @api private
         
     | 
| 
      
 18 
     | 
    
         
            +
                class Diagnostic
         
     | 
| 
      
 19 
     | 
    
         
            +
                  def initialize(document_encoding, offense, uri, cop_class)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @document_encoding = document_encoding
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @offense = offense
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @uri = uri
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @cop_class = cop_class
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  def to_lsp_code_actions
         
     | 
| 
      
 27 
     | 
    
         
            +
                    code_actions = []
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    code_actions << autocorrect_action if correctable?
         
     | 
| 
      
 30 
     | 
    
         
            +
                    code_actions << disable_line_action
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    code_actions
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
         
     | 
| 
      
 36 
     | 
    
         
            +
                  def to_lsp_diagnostic(config)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    highlighted = @offense.highlighted_area
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    LanguageServer::Protocol::Interface::Diagnostic.new(
         
     | 
| 
      
 40 
     | 
    
         
            +
                      message: message,
         
     | 
| 
      
 41 
     | 
    
         
            +
                      source: 'RuboCop',
         
     | 
| 
      
 42 
     | 
    
         
            +
                      code: @offense.cop_name,
         
     | 
| 
      
 43 
     | 
    
         
            +
                      code_description: code_description(config),
         
     | 
| 
      
 44 
     | 
    
         
            +
                      severity: severity,
         
     | 
| 
      
 45 
     | 
    
         
            +
                      range: LanguageServer::Protocol::Interface::Range.new(
         
     | 
| 
      
 46 
     | 
    
         
            +
                        start: LanguageServer::Protocol::Interface::Position.new(
         
     | 
| 
      
 47 
     | 
    
         
            +
                          line: @offense.line - 1,
         
     | 
| 
      
 48 
     | 
    
         
            +
                          character: highlighted.begin_pos
         
     | 
| 
      
 49 
     | 
    
         
            +
                        ),
         
     | 
| 
      
 50 
     | 
    
         
            +
                        end: LanguageServer::Protocol::Interface::Position.new(
         
     | 
| 
      
 51 
     | 
    
         
            +
                          line: @offense.line - 1,
         
     | 
| 
      
 52 
     | 
    
         
            +
                          character: highlighted.end_pos
         
     | 
| 
      
 53 
     | 
    
         
            +
                        )
         
     | 
| 
      
 54 
     | 
    
         
            +
                      ),
         
     | 
| 
      
 55 
     | 
    
         
            +
                      data: {
         
     | 
| 
      
 56 
     | 
    
         
            +
                        correctable: correctable?,
         
     | 
| 
      
 57 
     | 
    
         
            +
                        code_actions: to_lsp_code_actions
         
     | 
| 
      
 58 
     | 
    
         
            +
                      }
         
     | 
| 
      
 59 
     | 
    
         
            +
                    )
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
                  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                  private
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  def message
         
     | 
| 
      
 66 
     | 
    
         
            +
                    message = @offense.message
         
     | 
| 
      
 67 
     | 
    
         
            +
                    message += "\n\nThis offense is not autocorrectable.\n" unless correctable?
         
     | 
| 
      
 68 
     | 
    
         
            +
                    message
         
     | 
| 
      
 69 
     | 
    
         
            +
                  end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  def severity
         
     | 
| 
      
 72 
     | 
    
         
            +
                    Severity.find_by(@offense.severity.name)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                  def code_description(config)
         
     | 
| 
      
 76 
     | 
    
         
            +
                    return unless @cop_class
         
     | 
| 
      
 77 
     | 
    
         
            +
                    return unless (doc_url = @cop_class.documentation_url(config))
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    LanguageServer::Protocol::Interface::CodeDescription.new(href: doc_url)
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  # rubocop:disable Layout/LineLength, Metrics/MethodLength
         
     | 
| 
      
 83 
     | 
    
         
            +
                  def autocorrect_action
         
     | 
| 
      
 84 
     | 
    
         
            +
                    LanguageServer::Protocol::Interface::CodeAction.new(
         
     | 
| 
      
 85 
     | 
    
         
            +
                      title: "Autocorrect #{@offense.cop_name}",
         
     | 
| 
      
 86 
     | 
    
         
            +
                      kind: LanguageServer::Protocol::Constant::CodeActionKind::QUICK_FIX,
         
     | 
| 
      
 87 
     | 
    
         
            +
                      edit: LanguageServer::Protocol::Interface::WorkspaceEdit.new(
         
     | 
| 
      
 88 
     | 
    
         
            +
                        document_changes: [
         
     | 
| 
      
 89 
     | 
    
         
            +
                          LanguageServer::Protocol::Interface::TextDocumentEdit.new(
         
     | 
| 
      
 90 
     | 
    
         
            +
                            text_document: LanguageServer::Protocol::Interface::OptionalVersionedTextDocumentIdentifier.new(
         
     | 
| 
      
 91 
     | 
    
         
            +
                              uri: ensure_uri_scheme(@uri.to_s).to_s,
         
     | 
| 
      
 92 
     | 
    
         
            +
                              version: nil
         
     | 
| 
      
 93 
     | 
    
         
            +
                            ),
         
     | 
| 
      
 94 
     | 
    
         
            +
                            edits: correctable? ? offense_replacements : []
         
     | 
| 
      
 95 
     | 
    
         
            +
                          )
         
     | 
| 
      
 96 
     | 
    
         
            +
                        ]
         
     | 
| 
      
 97 
     | 
    
         
            +
                      ),
         
     | 
| 
      
 98 
     | 
    
         
            +
                      is_preferred: true
         
     | 
| 
      
 99 
     | 
    
         
            +
                    )
         
     | 
| 
      
 100 
     | 
    
         
            +
                  end
         
     | 
| 
      
 101 
     | 
    
         
            +
                  # rubocop:enable Layout/LineLength, Metrics/MethodLength
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                  # rubocop:disable Metrics/MethodLength
         
     | 
| 
      
 104 
     | 
    
         
            +
                  def offense_replacements
         
     | 
| 
      
 105 
     | 
    
         
            +
                    @offense.corrector.as_replacements.map do |range, replacement|
         
     | 
| 
      
 106 
     | 
    
         
            +
                      LanguageServer::Protocol::Interface::TextEdit.new(
         
     | 
| 
      
 107 
     | 
    
         
            +
                        range: LanguageServer::Protocol::Interface::Range.new(
         
     | 
| 
      
 108 
     | 
    
         
            +
                          start: LanguageServer::Protocol::Interface::Position.new(
         
     | 
| 
      
 109 
     | 
    
         
            +
                            line: range.line - 1,
         
     | 
| 
      
 110 
     | 
    
         
            +
                            character: range.column
         
     | 
| 
      
 111 
     | 
    
         
            +
                          ),
         
     | 
| 
      
 112 
     | 
    
         
            +
                          end: LanguageServer::Protocol::Interface::Position.new(
         
     | 
| 
      
 113 
     | 
    
         
            +
                            line: range.last_line - 1,
         
     | 
| 
      
 114 
     | 
    
         
            +
                            character: range.last_column
         
     | 
| 
      
 115 
     | 
    
         
            +
                          )
         
     | 
| 
      
 116 
     | 
    
         
            +
                        ),
         
     | 
| 
      
 117 
     | 
    
         
            +
                        new_text: replacement
         
     | 
| 
      
 118 
     | 
    
         
            +
                      )
         
     | 
| 
      
 119 
     | 
    
         
            +
                    end
         
     | 
| 
      
 120 
     | 
    
         
            +
                  end
         
     | 
| 
      
 121 
     | 
    
         
            +
                  # rubocop:enable Metrics/MethodLength
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                  # rubocop:disable Layout/LineLength, Metrics/MethodLength
         
     | 
| 
      
 124 
     | 
    
         
            +
                  def disable_line_action
         
     | 
| 
      
 125 
     | 
    
         
            +
                    LanguageServer::Protocol::Interface::CodeAction.new(
         
     | 
| 
      
 126 
     | 
    
         
            +
                      title: "Disable #{@offense.cop_name} for this line",
         
     | 
| 
      
 127 
     | 
    
         
            +
                      kind: LanguageServer::Protocol::Constant::CodeActionKind::QUICK_FIX,
         
     | 
| 
      
 128 
     | 
    
         
            +
                      edit: LanguageServer::Protocol::Interface::WorkspaceEdit.new(
         
     | 
| 
      
 129 
     | 
    
         
            +
                        document_changes: [
         
     | 
| 
      
 130 
     | 
    
         
            +
                          LanguageServer::Protocol::Interface::TextDocumentEdit.new(
         
     | 
| 
      
 131 
     | 
    
         
            +
                            text_document: LanguageServer::Protocol::Interface::OptionalVersionedTextDocumentIdentifier.new(
         
     | 
| 
      
 132 
     | 
    
         
            +
                              uri: ensure_uri_scheme(@uri.to_s).to_s,
         
     | 
| 
      
 133 
     | 
    
         
            +
                              version: nil
         
     | 
| 
      
 134 
     | 
    
         
            +
                            ),
         
     | 
| 
      
 135 
     | 
    
         
            +
                            edits: line_disable_comment
         
     | 
| 
      
 136 
     | 
    
         
            +
                          )
         
     | 
| 
      
 137 
     | 
    
         
            +
                        ]
         
     | 
| 
      
 138 
     | 
    
         
            +
                      )
         
     | 
| 
      
 139 
     | 
    
         
            +
                    )
         
     | 
| 
      
 140 
     | 
    
         
            +
                  end
         
     | 
| 
      
 141 
     | 
    
         
            +
                  # rubocop:enable Layout/LineLength, Metrics/MethodLength
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                  def line_disable_comment
         
     | 
| 
      
 144 
     | 
    
         
            +
                    new_text = if @offense.source_line.include?(' # rubocop:disable ')
         
     | 
| 
      
 145 
     | 
    
         
            +
                                 ",#{@offense.cop_name}"
         
     | 
| 
      
 146 
     | 
    
         
            +
                               else
         
     | 
| 
      
 147 
     | 
    
         
            +
                                 " # rubocop:disable #{@offense.cop_name}"
         
     | 
| 
      
 148 
     | 
    
         
            +
                               end
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                    eol = LanguageServer::Protocol::Interface::Position.new(
         
     | 
| 
      
 151 
     | 
    
         
            +
                      line: @offense.line - 1,
         
     | 
| 
      
 152 
     | 
    
         
            +
                      character: length_of_line(@offense.source_line)
         
     | 
| 
      
 153 
     | 
    
         
            +
                    )
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                    # TODO: fails for multiline strings - may be preferable to use block
         
     | 
| 
      
 156 
     | 
    
         
            +
                    # comments to disable some offenses
         
     | 
| 
      
 157 
     | 
    
         
            +
                    inline_comment = LanguageServer::Protocol::Interface::TextEdit.new(
         
     | 
| 
      
 158 
     | 
    
         
            +
                      range: LanguageServer::Protocol::Interface::Range.new(start: eol, end: eol),
         
     | 
| 
      
 159 
     | 
    
         
            +
                      new_text: new_text
         
     | 
| 
      
 160 
     | 
    
         
            +
                    )
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                    [inline_comment]
         
     | 
| 
      
 163 
     | 
    
         
            +
                  end
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
                  def length_of_line(line)
         
     | 
| 
      
 166 
     | 
    
         
            +
                    if @document_encoding == Encoding::UTF_16LE
         
     | 
| 
      
 167 
     | 
    
         
            +
                      line_length = 0
         
     | 
| 
      
 168 
     | 
    
         
            +
                      line.codepoints.each do |codepoint|
         
     | 
| 
      
 169 
     | 
    
         
            +
                        line_length += 1
         
     | 
| 
      
 170 
     | 
    
         
            +
                        line_length += 1 if codepoint > RubyLsp::Document::Scanner::SURROGATE_PAIR_START
         
     | 
| 
      
 171 
     | 
    
         
            +
                      end
         
     | 
| 
      
 172 
     | 
    
         
            +
                      line_length
         
     | 
| 
      
 173 
     | 
    
         
            +
                    else
         
     | 
| 
      
 174 
     | 
    
         
            +
                      line.length
         
     | 
| 
      
 175 
     | 
    
         
            +
                    end
         
     | 
| 
      
 176 
     | 
    
         
            +
                  end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                  def correctable?
         
     | 
| 
      
 179 
     | 
    
         
            +
                    !@offense.corrector.nil?
         
     | 
| 
      
 180 
     | 
    
         
            +
                  end
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
                  def ensure_uri_scheme(uri)
         
     | 
| 
      
 183 
     | 
    
         
            +
                    uri = URI.parse(uri)
         
     | 
| 
      
 184 
     | 
    
         
            +
                    uri.scheme = 'file' if uri.scheme.nil?
         
     | 
| 
      
 185 
     | 
    
         
            +
                    uri
         
     | 
| 
      
 186 
     | 
    
         
            +
                  end
         
     | 
| 
      
 187 
     | 
    
         
            +
                end
         
     | 
| 
      
 188 
     | 
    
         
            +
              end
         
     | 
| 
      
 189 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/rubocop/lsp/logger.rb
    CHANGED