rubocop 1.75.8 → 1.81.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +20 -16
 - data/config/default.yml +121 -28
 - data/config/obsoletion.yml +6 -3
 - data/exe/rubocop +1 -8
 - data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
 - data/lib/rubocop/cli.rb +18 -3
 - data/lib/rubocop/config_loader.rb +4 -39
 - data/lib/rubocop/config_loader_resolver.rb +5 -4
 - data/lib/rubocop/config_store.rb +5 -0
 - data/lib/rubocop/cop/autocorrect_logic.rb +4 -4
 - data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
 - data/lib/rubocop/cop/correctors/alignment_corrector.rb +7 -4
 - data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
 - data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
 - data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
 - data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
 - data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
 - data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
 - data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
 - data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
 - data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +4 -1
 - data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
 - data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
 - data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
 - data/lib/rubocop/cop/layout/class_structure.rb +1 -1
 - data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
 - data/lib/rubocop/cop/layout/dot_position.rb +1 -1
 - data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
 - data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
 - data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -1
 - data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
 - data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
 - data/lib/rubocop/cop/layout/hash_alignment.rb +2 -5
 - data/lib/rubocop/cop/layout/line_length.rb +35 -6
 - data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
 - data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +8 -0
 - data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
 - data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
 - data/lib/rubocop/cop/layout/space_before_brackets.rb +2 -9
 - data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
 - data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
 - data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
 - data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
 - data/lib/rubocop/cop/lint/cop_directive_syntax.rb +13 -7
 - data/lib/rubocop/cop/lint/debugger.rb +0 -2
 - data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
 - data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
 - data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
 - data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
 - data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
 - data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
 - data/lib/rubocop/cop/lint/literal_as_condition.rb +34 -28
 - data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +17 -8
 - data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
 - data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
 - data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
 - data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
 - data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
 - data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
 - data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
 - data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
 - data/lib/rubocop/cop/lint/self_assignment.rb +31 -5
 - data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
 - data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
 - data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
 - data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
 - data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
 - data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
 - data/lib/rubocop/cop/lint/useless_or.rb +98 -0
 - data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
 - data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
 - data/lib/rubocop/cop/lint/void.rb +7 -0
 - data/lib/rubocop/cop/message_annotator.rb +1 -1
 - data/lib/rubocop/cop/mixin/alignment.rb +1 -1
 - data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
 - data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
 - data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
 - data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
 - data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
 - data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
 - data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
 - data/lib/rubocop/cop/naming/file_name.rb +2 -2
 - data/lib/rubocop/cop/naming/method_name.rb +129 -13
 - data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
 - data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
 - data/lib/rubocop/cop/security/eval.rb +2 -1
 - data/lib/rubocop/cop/security/json_load.rb +33 -11
 - data/lib/rubocop/cop/security/open.rb +1 -0
 - data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
 - data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
 - data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
 - data/lib/rubocop/cop/style/array_intersect.rb +99 -35
 - data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
 - data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
 - data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
 - data/lib/rubocop/cop/style/case_like_if.rb +1 -1
 - data/lib/rubocop/cop/style/collection_querying.rb +167 -0
 - data/lib/rubocop/cop/style/conditional_assignment.rb +11 -5
 - data/lib/rubocop/cop/style/constant_visibility.rb +14 -9
 - data/lib/rubocop/cop/style/dig_chain.rb +1 -1
 - data/lib/rubocop/cop/style/double_negation.rb +1 -1
 - data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
 - data/lib/rubocop/cop/style/endless_method.rb +15 -2
 - data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
 - data/lib/rubocop/cop/style/exponential_notation.rb +3 -2
 - data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
 - data/lib/rubocop/cop/style/float_division.rb +15 -1
 - data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
 - data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
 - data/lib/rubocop/cop/style/if_unless_modifier.rb +13 -6
 - data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
 - data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
 - data/lib/rubocop/cop/style/it_assignment.rb +69 -12
 - data/lib/rubocop/cop/style/it_block_parameter.rb +36 -15
 - data/lib/rubocop/cop/style/map_to_hash.rb +1 -3
 - data/lib/rubocop/cop/style/map_to_set.rb +1 -3
 - data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -6
 - data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
 - data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
 - data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
 - data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
 - data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
 - data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
 - data/lib/rubocop/cop/style/redundant_begin.rb +34 -0
 - data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
 - data/lib/rubocop/cop/style/redundant_format.rb +26 -5
 - data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
 - data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_parentheses.rb +55 -16
 - data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
 - data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
 - data/lib/rubocop/cop/style/redundant_self.rb +8 -5
 - data/lib/rubocop/cop/style/safe_navigation.rb +44 -12
 - data/lib/rubocop/cop/style/semicolon.rb +23 -7
 - data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
 - data/lib/rubocop/cop/style/sole_nested_conditional.rb +40 -3
 - data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
 - data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
 - data/lib/rubocop/cop/style/symbol_array.rb +1 -1
 - data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
 - data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
 - data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
 - data/lib/rubocop/cop/style/unless_else.rb +10 -9
 - data/lib/rubocop/cop/utils/format_string.rb +10 -0
 - data/lib/rubocop/cop/variable_force/variable.rb +1 -1
 - data/lib/rubocop/cop/variable_force.rb +25 -8
 - data/lib/rubocop/cops_documentation_generator.rb +5 -4
 - data/lib/rubocop/formatter/disabled_config_formatter.rb +18 -5
 - data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
 - data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
 - data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
 - data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
 - data/lib/rubocop/lsp/diagnostic.rb +25 -24
 - data/lib/rubocop/lsp/routes.rb +65 -9
 - data/lib/rubocop/lsp/runtime.rb +2 -2
 - data/lib/rubocop/lsp/server.rb +2 -2
 - data/lib/rubocop/lsp/stdin_runner.rb +0 -16
 - data/lib/rubocop/pending_cops_reporter.rb +56 -0
 - data/lib/rubocop/result_cache.rb +14 -12
 - data/lib/rubocop/rspec/expect_offense.rb +9 -3
 - data/lib/rubocop/runner.rb +6 -4
 - data/lib/rubocop/server/cache.rb +4 -2
 - data/lib/rubocop/server/client_command/base.rb +10 -0
 - data/lib/rubocop/server/client_command/exec.rb +2 -1
 - data/lib/rubocop/server/client_command/start.rb +11 -1
 - data/lib/rubocop/target_finder.rb +9 -9
 - data/lib/rubocop/target_ruby.rb +10 -1
 - data/lib/rubocop/version.rb +1 -1
 - data/lib/rubocop.rb +12 -1
 - data/lib/ruby_lsp/rubocop/addon.rb +25 -10
 - data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
 - metadata +18 -7
 
| 
         @@ -25,20 +25,24 @@ module RuboCop 
     | 
|
| 
       25 
25 
     | 
    
         
             
                    config.for_cop('Layout/LineLength')['AllowURI']
         
     | 
| 
       26 
26 
     | 
    
         
             
                  end
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
                  def  
     | 
| 
       29 
     | 
    
         
            -
                     
     | 
| 
      
 28 
     | 
    
         
            +
                  def allow_qualified_name?
         
     | 
| 
      
 29 
     | 
    
         
            +
                    config.for_cop('Layout/LineLength')['AllowQualifiedName']
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  def allowed_position?(line, range)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    range.begin < max_line_length && range.end == line_length(line)
         
     | 
| 
       30 
34 
     | 
    
         
             
                  end
         
     | 
| 
       31 
35 
     | 
    
         | 
| 
       32 
36 
     | 
    
         
             
                  def line_length(line)
         
     | 
| 
       33 
37 
     | 
    
         
             
                    line.length + indentation_difference(line)
         
     | 
| 
       34 
38 
     | 
    
         
             
                  end
         
     | 
| 
       35 
39 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
                  def  
     | 
| 
       37 
     | 
    
         
            -
                     
     | 
| 
       38 
     | 
    
         
            -
                    return nil unless  
     | 
| 
      
 40 
     | 
    
         
            +
                  def find_excessive_range(line, type)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    last_match = (type == :uri ? match_uris(line) : match_qualified_names(line)).last
         
     | 
| 
      
 42 
     | 
    
         
            +
                    return nil unless last_match
         
     | 
| 
       39 
43 
     | 
    
         | 
| 
       40 
     | 
    
         
            -
                    begin_position, end_position =  
     | 
| 
       41 
     | 
    
         
            -
                    end_position =  
     | 
| 
      
 44 
     | 
    
         
            +
                    begin_position, end_position = last_match.offset(0)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    end_position = extend_end_position(line, end_position)
         
     | 
| 
       42 
46 
     | 
    
         | 
| 
       43 
47 
     | 
    
         
             
                    line_indentation_difference = indentation_difference(line)
         
     | 
| 
       44 
48 
     | 
    
         
             
                    begin_position += line_indentation_difference
         
     | 
| 
         @@ -57,6 +61,14 @@ module RuboCop 
     | 
|
| 
       57 
61 
     | 
    
         
             
                    matches
         
     | 
| 
       58 
62 
     | 
    
         
             
                  end
         
     | 
| 
       59 
63 
     | 
    
         | 
| 
      
 64 
     | 
    
         
            +
                  def match_qualified_names(string)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    matches = []
         
     | 
| 
      
 66 
     | 
    
         
            +
                    string.scan(qualified_name_regexp) do
         
     | 
| 
      
 67 
     | 
    
         
            +
                      matches << $LAST_MATCH_INFO
         
     | 
| 
      
 68 
     | 
    
         
            +
                    end
         
     | 
| 
      
 69 
     | 
    
         
            +
                    matches
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
       60 
72 
     | 
    
         
             
                  def indentation_difference(line)
         
     | 
| 
       61 
73 
     | 
    
         
             
                    return 0 unless tab_indentation_width
         
     | 
| 
       62 
74 
     | 
    
         | 
| 
         @@ -70,7 +82,7 @@ module RuboCop 
     | 
|
| 
       70 
82 
     | 
    
         
             
                    index * (tab_indentation_width - 1)
         
     | 
| 
       71 
83 
     | 
    
         
             
                  end
         
     | 
| 
       72 
84 
     | 
    
         | 
| 
       73 
     | 
    
         
            -
                  def  
     | 
| 
      
 85 
     | 
    
         
            +
                  def extend_end_position(line, end_position)
         
     | 
| 
       74 
86 
     | 
    
         
             
                    # Extend the end position YARD comments with linked URLs of the form {<uri> <title>}
         
     | 
| 
       75 
87 
     | 
    
         
             
                    if line&.match(/{(\s|\S)*}$/)
         
     | 
| 
       76 
88 
     | 
    
         
             
                      match = line[end_position..line_length(line)]&.match(/(\s|\S)*}/)
         
     | 
| 
         @@ -101,6 +113,10 @@ module RuboCop 
     | 
|
| 
       101 
113 
     | 
    
         
             
                    end
         
     | 
| 
       102 
114 
     | 
    
         
             
                  end
         
     | 
| 
       103 
115 
     | 
    
         | 
| 
      
 116 
     | 
    
         
            +
                  def qualified_name_regexp
         
     | 
| 
      
 117 
     | 
    
         
            +
                    /\b(?:[A-Z][A-Za-z0-9_]*::)+[A-Za-z_][A-Za-z0-9_]*\b/
         
     | 
| 
      
 118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
       104 
120 
     | 
    
         
             
                  def valid_uri?(uri_ish_string)
         
     | 
| 
       105 
121 
     | 
    
         
             
                    URI.parse(uri_ish_string)
         
     | 
| 
       106 
122 
     | 
    
         
             
                    true
         
     | 
| 
         @@ -24,7 +24,7 @@ module RuboCop 
     | 
|
| 
       24 
24 
     | 
    
         
             
                    gem_canonical_name(string_a) < gem_canonical_name(string_b)
         
     | 
| 
       25 
25 
     | 
    
         
             
                  end
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
                  def consecutive_lines(previous, current)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  def consecutive_lines?(previous, current)
         
     | 
| 
       28 
28 
     | 
    
         
             
                    first_line = get_source_range(current, treat_comments_as_separators).first_line
         
     | 
| 
       29 
29 
     | 
    
         
             
                    previous.source_range.last_line == first_line - 1
         
     | 
| 
       30 
30 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -140,7 +140,7 @@ module RuboCop 
     | 
|
| 
       140 
140 
     | 
    
         
             
                  end
         
     | 
| 
       141 
141 
     | 
    
         | 
| 
       142 
142 
     | 
    
         
             
                  def last_item_precedes_newline?(node)
         
     | 
| 
       143 
     | 
    
         
            -
                    after_last_item = node.children.last.source_range.end.join(node. 
     | 
| 
      
 143 
     | 
    
         
            +
                    after_last_item = node.children.last.source_range.end.join(node.source_range.end)
         
     | 
| 
       144 
144 
     | 
    
         | 
| 
       145 
145 
     | 
    
         
             
                    after_last_item.source.start_with?(/,?\s*(#.*)?\n/)
         
     | 
| 
       146 
146 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -152,7 +152,7 @@ module RuboCop 
     | 
|
| 
       152 
152 
     | 
    
         | 
| 
       153 
153 
     | 
    
         
             
                        const_namespace, const_name = *const
         
     | 
| 
       154 
154 
     | 
    
         
             
                        next if name != const_name && !match_acronym?(name, const_name)
         
     | 
| 
       155 
     | 
    
         
            -
                        next unless namespace.empty? ||  
     | 
| 
      
 155 
     | 
    
         
            +
                        next unless namespace.empty? || namespace_matches?(child, const_namespace, namespace)
         
     | 
| 
       156 
156 
     | 
    
         | 
| 
       157 
157 
     | 
    
         
             
                        return node
         
     | 
| 
       158 
158 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -169,7 +169,7 @@ module RuboCop 
     | 
|
| 
       169 
169 
     | 
    
         
             
                      s(:const, namespace, name) if name
         
     | 
| 
       170 
170 
     | 
    
         
             
                    end
         
     | 
| 
       171 
171 
     | 
    
         | 
| 
       172 
     | 
    
         
            -
                    def  
     | 
| 
      
 172 
     | 
    
         
            +
                    def namespace_matches?(node, namespace, expected)
         
     | 
| 
       173 
173 
     | 
    
         
             
                      match_partial = partial_matcher!(expected)
         
     | 
| 
       174 
174 
     | 
    
         | 
| 
       175 
175 
     | 
    
         
             
                      match_partial.call(namespace)
         
     | 
| 
         @@ -39,6 +39,26 @@ module RuboCop 
     | 
|
| 
       39 
39 
     | 
    
         
             
                  #   # good
         
     | 
| 
       40 
40 
     | 
    
         
             
                  #   def foo_bar; end
         
     | 
| 
       41 
41 
     | 
    
         
             
                  #
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 43 
     | 
    
         
            +
                  #   define_method :fooBar do
         
     | 
| 
      
 44 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 45 
     | 
    
         
            +
                  #
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 47 
     | 
    
         
            +
                  #   define_method :foo_bar do
         
     | 
| 
      
 48 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 49 
     | 
    
         
            +
                  #
         
     | 
| 
      
 50 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 51 
     | 
    
         
            +
                  #   Struct.new(:fooBar)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  #
         
     | 
| 
      
 53 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 54 
     | 
    
         
            +
                  #   Struct.new(:foo_bar)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  #
         
     | 
| 
      
 56 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 57 
     | 
    
         
            +
                  #   alias_method :fooBar, :some_method
         
     | 
| 
      
 58 
     | 
    
         
            +
                  #
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 60 
     | 
    
         
            +
                  #   alias_method :foo_bar, :some_method
         
     | 
| 
      
 61 
     | 
    
         
            +
                  #
         
     | 
| 
       42 
62 
     | 
    
         
             
                  # @example EnforcedStyle: camelCase
         
     | 
| 
       43 
63 
     | 
    
         
             
                  #   # bad
         
     | 
| 
       44 
64 
     | 
    
         
             
                  #   def foo_bar; end
         
     | 
| 
         @@ -46,6 +66,26 @@ module RuboCop 
     | 
|
| 
       46 
66 
     | 
    
         
             
                  #   # good
         
     | 
| 
       47 
67 
     | 
    
         
             
                  #   def fooBar; end
         
     | 
| 
       48 
68 
     | 
    
         
             
                  #
         
     | 
| 
      
 69 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 70 
     | 
    
         
            +
                  #   define_method :foo_bar do
         
     | 
| 
      
 71 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 72 
     | 
    
         
            +
                  #
         
     | 
| 
      
 73 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 74 
     | 
    
         
            +
                  #   define_method :fooBar do
         
     | 
| 
      
 75 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 76 
     | 
    
         
            +
                  #
         
     | 
| 
      
 77 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 78 
     | 
    
         
            +
                  #   Struct.new(:foo_bar)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  #
         
     | 
| 
      
 80 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 81 
     | 
    
         
            +
                  #   Struct.new(:fooBar)
         
     | 
| 
      
 82 
     | 
    
         
            +
                  #
         
     | 
| 
      
 83 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 84 
     | 
    
         
            +
                  #   alias_method :foo_bar, :some_method
         
     | 
| 
      
 85 
     | 
    
         
            +
                  #
         
     | 
| 
      
 86 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 87 
     | 
    
         
            +
                  #   alias_method :fooBar, :some_method
         
     | 
| 
      
 88 
     | 
    
         
            +
                  #
         
     | 
| 
       49 
89 
     | 
    
         
             
                  # @example ForbiddenIdentifiers: ['def', 'super']
         
     | 
| 
       50 
90 
     | 
    
         
             
                  #   # bad
         
     | 
| 
       51 
91 
     | 
    
         
             
                  #   def def; end
         
     | 
| 
         @@ -66,13 +106,81 @@ module RuboCop 
     | 
|
| 
       66 
106 
     | 
    
         
             
                    MSG = 'Use %<style>s for method names.'
         
     | 
| 
       67 
107 
     | 
    
         
             
                    MSG_FORBIDDEN = '`%<identifier>s` is forbidden, use another method name instead.'
         
     | 
| 
       68 
108 
     | 
    
         | 
| 
      
 109 
     | 
    
         
            +
                    OPERATOR_METHODS = %i[| ^ & <=> == === =~ > >= < <= << >> + - * /
         
     | 
| 
      
 110 
     | 
    
         
            +
                                          % ** ~ +@ -@ !@ ~@ [] []= ! != !~ `].to_set.freeze
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
       69 
112 
     | 
    
         
             
                    # @!method sym_name(node)
         
     | 
| 
       70 
113 
     | 
    
         
             
                    def_node_matcher :sym_name, '(sym $_name)'
         
     | 
| 
       71 
114 
     | 
    
         | 
| 
       72 
115 
     | 
    
         
             
                    # @!method str_name(node)
         
     | 
| 
       73 
116 
     | 
    
         
             
                    def_node_matcher :str_name, '(str $_name)'
         
     | 
| 
       74 
117 
     | 
    
         | 
| 
      
 118 
     | 
    
         
            +
                    # @!method new_struct?(node)
         
     | 
| 
      
 119 
     | 
    
         
            +
                    def_node_matcher :new_struct?, '(send (const {nil? cbase} :Struct) :new ...)'
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
                    # @!method define_data?(node)
         
     | 
| 
      
 122 
     | 
    
         
            +
                    def_node_matcher :define_data?, '(send (const {nil? cbase} :Data) :define ...)'
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
       75 
124 
     | 
    
         
             
                    def on_send(node)
         
     | 
| 
      
 125 
     | 
    
         
            +
                      if node.method?(:define_method) || node.method?(:define_singleton_method)
         
     | 
| 
      
 126 
     | 
    
         
            +
                        handle_define_method(node)
         
     | 
| 
      
 127 
     | 
    
         
            +
                      elsif new_struct?(node)
         
     | 
| 
      
 128 
     | 
    
         
            +
                        handle_new_struct(node)
         
     | 
| 
      
 129 
     | 
    
         
            +
                      elsif define_data?(node)
         
     | 
| 
      
 130 
     | 
    
         
            +
                        handle_define_data(node)
         
     | 
| 
      
 131 
     | 
    
         
            +
                      elsif node.method?(:alias_method)
         
     | 
| 
      
 132 
     | 
    
         
            +
                        handle_alias_method(node)
         
     | 
| 
      
 133 
     | 
    
         
            +
                      else
         
     | 
| 
      
 134 
     | 
    
         
            +
                        handle_attr_accessor(node)
         
     | 
| 
      
 135 
     | 
    
         
            +
                      end
         
     | 
| 
      
 136 
     | 
    
         
            +
                    end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                    def on_def(node)
         
     | 
| 
      
 139 
     | 
    
         
            +
                      return if node.operator_method? || matches_allowed_pattern?(node.method_name)
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                      if forbidden_name?(node.method_name.to_s)
         
     | 
| 
      
 142 
     | 
    
         
            +
                        register_forbidden_name(node)
         
     | 
| 
      
 143 
     | 
    
         
            +
                      else
         
     | 
| 
      
 144 
     | 
    
         
            +
                        check_name(node, node.method_name, node.loc.name)
         
     | 
| 
      
 145 
     | 
    
         
            +
                      end
         
     | 
| 
      
 146 
     | 
    
         
            +
                    end
         
     | 
| 
      
 147 
     | 
    
         
            +
                    alias on_defs on_def
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                    def on_alias(node)
         
     | 
| 
      
 150 
     | 
    
         
            +
                      return unless (new_identifier = node.new_identifier).sym_type?
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                      handle_method_name(new_identifier, new_identifier.value)
         
     | 
| 
      
 153 
     | 
    
         
            +
                    end
         
     | 
| 
      
 154 
     | 
    
         
            +
             
     | 
| 
      
 155 
     | 
    
         
            +
                    private
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                    def handle_define_method(node)
         
     | 
| 
      
 158 
     | 
    
         
            +
                      return unless node.first_argument&.type?(:str, :sym)
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                      handle_method_name(node, node.first_argument.value)
         
     | 
| 
      
 161 
     | 
    
         
            +
                    end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                    def handle_new_struct(node)
         
     | 
| 
      
 164 
     | 
    
         
            +
                      arguments = node.first_argument&.str_type? ? node.arguments[1..] : node.arguments
         
     | 
| 
      
 165 
     | 
    
         
            +
                      arguments.select { |argument| argument.type?(:sym, :str) }.each do |name|
         
     | 
| 
      
 166 
     | 
    
         
            +
                        handle_method_name(name, name.value)
         
     | 
| 
      
 167 
     | 
    
         
            +
                      end
         
     | 
| 
      
 168 
     | 
    
         
            +
                    end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
                    def handle_define_data(node)
         
     | 
| 
      
 171 
     | 
    
         
            +
                      node.arguments.select { |argument| argument.type?(:sym, :str) }.each do |name|
         
     | 
| 
      
 172 
     | 
    
         
            +
                        handle_method_name(name, name.value)
         
     | 
| 
      
 173 
     | 
    
         
            +
                      end
         
     | 
| 
      
 174 
     | 
    
         
            +
                    end
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
                    def handle_alias_method(node)
         
     | 
| 
      
 177 
     | 
    
         
            +
                      return unless node.arguments.size == 2
         
     | 
| 
      
 178 
     | 
    
         
            +
                      return unless node.first_argument.type?(:str, :sym)
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                      handle_method_name(node.first_argument, node.first_argument.value)
         
     | 
| 
      
 181 
     | 
    
         
            +
                    end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                    def handle_attr_accessor(node)
         
     | 
| 
       76 
184 
     | 
    
         
             
                      return unless (attrs = node.attribute_accessor?)
         
     | 
| 
       77 
185 
     | 
    
         | 
| 
       78 
186 
     | 
    
         
             
                      attrs.last.each do |name_item|
         
     | 
| 
         @@ -87,45 +195,53 @@ module RuboCop 
     | 
|
| 
       87 
195 
     | 
    
         
             
                      end
         
     | 
| 
       88 
196 
     | 
    
         
             
                    end
         
     | 
| 
       89 
197 
     | 
    
         | 
| 
       90 
     | 
    
         
            -
                    def  
     | 
| 
       91 
     | 
    
         
            -
                      return if  
     | 
| 
      
 198 
     | 
    
         
            +
                    def handle_method_name(node, name)
         
     | 
| 
      
 199 
     | 
    
         
            +
                      return if !name || matches_allowed_pattern?(name)
         
     | 
| 
       92 
200 
     | 
    
         | 
| 
       93 
     | 
    
         
            -
                      if forbidden_name?( 
     | 
| 
      
 201 
     | 
    
         
            +
                      if forbidden_name?(name.to_s)
         
     | 
| 
       94 
202 
     | 
    
         
             
                        register_forbidden_name(node)
         
     | 
| 
       95 
     | 
    
         
            -
                       
     | 
| 
       96 
     | 
    
         
            -
                        check_name(node,  
     | 
| 
      
 203 
     | 
    
         
            +
                      elsif !OPERATOR_METHODS.include?(name.to_sym)
         
     | 
| 
      
 204 
     | 
    
         
            +
                        check_name(node, name, range_position(node))
         
     | 
| 
       97 
205 
     | 
    
         
             
                      end
         
     | 
| 
       98 
206 
     | 
    
         
             
                    end
         
     | 
| 
       99 
     | 
    
         
            -
                    alias on_defs on_def
         
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
                    private
         
     | 
| 
       102 
207 
     | 
    
         | 
| 
       103 
208 
     | 
    
         
             
                    def forbidden_name?(name)
         
     | 
| 
       104 
209 
     | 
    
         
             
                      forbidden_identifier?(name) || forbidden_pattern?(name)
         
     | 
| 
       105 
210 
     | 
    
         
             
                    end
         
     | 
| 
       106 
211 
     | 
    
         | 
| 
      
 212 
     | 
    
         
            +
                    # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
         
     | 
| 
       107 
213 
     | 
    
         
             
                    def register_forbidden_name(node)
         
     | 
| 
       108 
214 
     | 
    
         
             
                      if node.any_def_type?
         
     | 
| 
       109 
215 
     | 
    
         
             
                        name_node = node.loc.name
         
     | 
| 
       110 
216 
     | 
    
         
             
                        method_name = node.method_name
         
     | 
| 
       111 
     | 
    
         
            -
                       
     | 
| 
       112 
     | 
    
         
            -
                         
     | 
| 
      
 217 
     | 
    
         
            +
                      elsif node.literal?
         
     | 
| 
      
 218 
     | 
    
         
            +
                        name_node = node
         
     | 
| 
      
 219 
     | 
    
         
            +
                        method_name = node.value
         
     | 
| 
      
 220 
     | 
    
         
            +
                      elsif (attrs = node.attribute_accessor?)
         
     | 
| 
       113 
221 
     | 
    
         
             
                        name_node = attrs.last.last
         
     | 
| 
       114 
222 
     | 
    
         
             
                        method_name = attr_name(name_node)
         
     | 
| 
      
 223 
     | 
    
         
            +
                      else
         
     | 
| 
      
 224 
     | 
    
         
            +
                        name_node = node.first_argument
         
     | 
| 
      
 225 
     | 
    
         
            +
                        method_name = node.first_argument.value
         
     | 
| 
       115 
226 
     | 
    
         
             
                      end
         
     | 
| 
       116 
227 
     | 
    
         
             
                      message = format(MSG_FORBIDDEN, identifier: method_name)
         
     | 
| 
       117 
228 
     | 
    
         
             
                      add_offense(name_node, message: message)
         
     | 
| 
       118 
229 
     | 
    
         
             
                    end
         
     | 
| 
      
 230 
     | 
    
         
            +
                    # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
         
     | 
| 
       119 
231 
     | 
    
         | 
| 
       120 
232 
     | 
    
         
             
                    def attr_name(name_item)
         
     | 
| 
       121 
233 
     | 
    
         
             
                      sym_name(name_item) || str_name(name_item)
         
     | 
| 
       122 
234 
     | 
    
         
             
                    end
         
     | 
| 
       123 
235 
     | 
    
         | 
| 
       124 
236 
     | 
    
         
             
                    def range_position(node)
         
     | 
| 
       125 
     | 
    
         
            -
                       
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
      
 237 
     | 
    
         
            +
                      if node.loc.respond_to?(:selector)
         
     | 
| 
      
 238 
     | 
    
         
            +
                        selector_end_pos = node.loc.selector.end_pos + 1
         
     | 
| 
      
 239 
     | 
    
         
            +
                        expr_end_pos = node.source_range.end_pos
         
     | 
| 
       127 
240 
     | 
    
         | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
      
 241 
     | 
    
         
            +
                        range_between(selector_end_pos, expr_end_pos)
         
     | 
| 
      
 242 
     | 
    
         
            +
                      else
         
     | 
| 
      
 243 
     | 
    
         
            +
                        node.source_range
         
     | 
| 
      
 244 
     | 
    
         
            +
                      end
         
     | 
| 
       129 
245 
     | 
    
         
             
                    end
         
     | 
| 
       130 
246 
     | 
    
         | 
| 
       131 
247 
     | 
    
         
             
                    def message(style)
         
     | 
| 
         @@ -0,0 +1,319 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Naming
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # Checks that predicate methods end with `?` and non-predicate methods do not.
         
     | 
| 
      
 7 
     | 
    
         
            +
                  #
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # The names of predicate methods (methods that return a boolean value) should end
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # in a question mark. Methods that don't return a boolean, shouldn't
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # end in a question mark.
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # The cop assesses a predicate method as one that returns boolean values. Likewise,
         
     | 
| 
      
 13 
     | 
    
         
            +
                  # a method that only returns literal values is assessed as non-predicate. Other predicate
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # method calls are assumed to return boolean values. The cop does not make an assessment
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # if the return type is unknown (non-predicate method calls, variables, etc.).
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #
         
     | 
| 
      
 17 
     | 
    
         
            +
                  # NOTE: The `initialize` method and operator methods (`def ==`, etc.) are ignored.
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # By default, the cop runs in `conservative` mode, which allows a method to be named
         
     | 
| 
      
 20 
     | 
    
         
            +
                  # with a question mark as long as at least one return value is boolean. In `aggressive`
         
     | 
| 
      
 21 
     | 
    
         
            +
                  # mode, methods with a question mark will register an offense if any known non-boolean
         
     | 
| 
      
 22 
     | 
    
         
            +
                  # return values are detected.
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #
         
     | 
| 
      
 24 
     | 
    
         
            +
                  # The cop also has `AllowedMethods` configuration in order to prevent the cop from
         
     | 
| 
      
 25 
     | 
    
         
            +
                  # registering an offense from a method name that does not confirm to the naming
         
     | 
| 
      
 26 
     | 
    
         
            +
                  # guidelines. By default, `call` is allowed. The cop also has `AllowedPatterns`
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # configuration to allow method names by regular expression.
         
     | 
| 
      
 28 
     | 
    
         
            +
                  #
         
     | 
| 
      
 29 
     | 
    
         
            +
                  # Although returning a call to another predicate method is treated as a boolean value,
         
     | 
| 
      
 30 
     | 
    
         
            +
                  # certain method names can be known to not return a boolean, despite ending in a `?`
         
     | 
| 
      
 31 
     | 
    
         
            +
                  # (for example, `Numeric#nonzero?` returns `self` or `nil`). These methods can be
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # configured using `NonBooleanPredicates`.
         
     | 
| 
      
 33 
     | 
    
         
            +
                  #
         
     | 
| 
      
 34 
     | 
    
         
            +
                  # The cop can furthermore be configured to allow all bang methods (method names
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # ending with `!`), with `AllowBangMethods: true` (default false).
         
     | 
| 
      
 36 
     | 
    
         
            +
                  #
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # @example Mode: conservative (default)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 39 
     | 
    
         
            +
                  #   def foo
         
     | 
| 
      
 40 
     | 
    
         
            +
                  #     bar == baz
         
     | 
| 
      
 41 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #
         
     | 
| 
      
 43 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 44 
     | 
    
         
            +
                  #   def foo?
         
     | 
| 
      
 45 
     | 
    
         
            +
                  #     bar == baz
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 47 
     | 
    
         
            +
                  #
         
     | 
| 
      
 48 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 49 
     | 
    
         
            +
                  #   def foo?
         
     | 
| 
      
 50 
     | 
    
         
            +
                  #     5
         
     | 
| 
      
 51 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 52 
     | 
    
         
            +
                  #
         
     | 
| 
      
 53 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 54 
     | 
    
         
            +
                  #   def foo
         
     | 
| 
      
 55 
     | 
    
         
            +
                  #     5
         
     | 
| 
      
 56 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 57 
     | 
    
         
            +
                  #
         
     | 
| 
      
 58 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #   def foo
         
     | 
| 
      
 60 
     | 
    
         
            +
                  #     x == y
         
     | 
| 
      
 61 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 62 
     | 
    
         
            +
                  #
         
     | 
| 
      
 63 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 64 
     | 
    
         
            +
                  #   def foo?
         
     | 
| 
      
 65 
     | 
    
         
            +
                  #     x == y
         
     | 
| 
      
 66 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 67 
     | 
    
         
            +
                  #
         
     | 
| 
      
 68 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 69 
     | 
    
         
            +
                  #   def foo
         
     | 
| 
      
 70 
     | 
    
         
            +
                  #     !x
         
     | 
| 
      
 71 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 72 
     | 
    
         
            +
                  #
         
     | 
| 
      
 73 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 74 
     | 
    
         
            +
                  #   def foo?
         
     | 
| 
      
 75 
     | 
    
         
            +
                  #     !x
         
     | 
| 
      
 76 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 77 
     | 
    
         
            +
                  #
         
     | 
| 
      
 78 
     | 
    
         
            +
                  #   # bad - returns the value of another predicate method
         
     | 
| 
      
 79 
     | 
    
         
            +
                  #   def foo
         
     | 
| 
      
 80 
     | 
    
         
            +
                  #     bar?
         
     | 
| 
      
 81 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 82 
     | 
    
         
            +
                  #
         
     | 
| 
      
 83 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 84 
     | 
    
         
            +
                  #   def foo?
         
     | 
| 
      
 85 
     | 
    
         
            +
                  #     bar?
         
     | 
| 
      
 86 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 87 
     | 
    
         
            +
                  #
         
     | 
| 
      
 88 
     | 
    
         
            +
                  #   # good - operator method
         
     | 
| 
      
 89 
     | 
    
         
            +
                  #   def ==(other)
         
     | 
| 
      
 90 
     | 
    
         
            +
                  #     hash == other.hash
         
     | 
| 
      
 91 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 92 
     | 
    
         
            +
                  #
         
     | 
| 
      
 93 
     | 
    
         
            +
                  #   # good - at least one return value is boolean
         
     | 
| 
      
 94 
     | 
    
         
            +
                  #   def foo?
         
     | 
| 
      
 95 
     | 
    
         
            +
                  #     return unless bar?
         
     | 
| 
      
 96 
     | 
    
         
            +
                  #     true
         
     | 
| 
      
 97 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 98 
     | 
    
         
            +
                  #
         
     | 
| 
      
 99 
     | 
    
         
            +
                  #   # ok - return type is not known
         
     | 
| 
      
 100 
     | 
    
         
            +
                  #   def foo?
         
     | 
| 
      
 101 
     | 
    
         
            +
                  #     bar
         
     | 
| 
      
 102 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 103 
     | 
    
         
            +
                  #
         
     | 
| 
      
 104 
     | 
    
         
            +
                  #   # ok - return type is not known
         
     | 
| 
      
 105 
     | 
    
         
            +
                  #   def foo
         
     | 
| 
      
 106 
     | 
    
         
            +
                  #     bar?
         
     | 
| 
      
 107 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 108 
     | 
    
         
            +
                  #
         
     | 
| 
      
 109 
     | 
    
         
            +
                  # @example Mode: aggressive
         
     | 
| 
      
 110 
     | 
    
         
            +
                  #   # bad - the method returns nil in some cases
         
     | 
| 
      
 111 
     | 
    
         
            +
                  #   def foo?
         
     | 
| 
      
 112 
     | 
    
         
            +
                  #     return unless bar?
         
     | 
| 
      
 113 
     | 
    
         
            +
                  #     true
         
     | 
| 
      
 114 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 115 
     | 
    
         
            +
                  #
         
     | 
| 
      
 116 
     | 
    
         
            +
                  # @example AllowedMethods: [call] (default)
         
     | 
| 
      
 117 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 118 
     | 
    
         
            +
                  #   def call
         
     | 
| 
      
 119 
     | 
    
         
            +
                  #     foo == bar
         
     | 
| 
      
 120 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 121 
     | 
    
         
            +
                  #
         
     | 
| 
      
 122 
     | 
    
         
            +
                  # @example AllowedPatterns: [\Afoo]
         
     | 
| 
      
 123 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 124 
     | 
    
         
            +
                  #   def foo?
         
     | 
| 
      
 125 
     | 
    
         
            +
                  #     'foo'
         
     | 
| 
      
 126 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 127 
     | 
    
         
            +
                  #
         
     | 
| 
      
 128 
     | 
    
         
            +
                  # @example AllowBangMethods: false (default)
         
     | 
| 
      
 129 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 130 
     | 
    
         
            +
                  #   def save!
         
     | 
| 
      
 131 
     | 
    
         
            +
                  #     true
         
     | 
| 
      
 132 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 133 
     | 
    
         
            +
                  #
         
     | 
| 
      
 134 
     | 
    
         
            +
                  # @example AllowBangMethods: true
         
     | 
| 
      
 135 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 136 
     | 
    
         
            +
                  #   def save!
         
     | 
| 
      
 137 
     | 
    
         
            +
                  #     true
         
     | 
| 
      
 138 
     | 
    
         
            +
                  #   end
         
     | 
| 
      
 139 
     | 
    
         
            +
                  #
         
     | 
| 
      
 140 
     | 
    
         
            +
                  class PredicateMethod < Base
         
     | 
| 
      
 141 
     | 
    
         
            +
                    include AllowedMethods
         
     | 
| 
      
 142 
     | 
    
         
            +
                    include AllowedPattern
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                    MSG_PREDICATE = 'Predicate method names should end with `?`.'
         
     | 
| 
      
 145 
     | 
    
         
            +
                    MSG_NON_PREDICATE = 'Non-predicate method names should not end with `?`.'
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                    def on_def(node)
         
     | 
| 
      
 148 
     | 
    
         
            +
                      return if allowed?(node)
         
     | 
| 
      
 149 
     | 
    
         
            +
             
     | 
| 
      
 150 
     | 
    
         
            +
                      return_values = return_values(node.body)
         
     | 
| 
      
 151 
     | 
    
         
            +
                      return if acceptable?(return_values)
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                      if node.predicate_method? && potential_non_predicate?(return_values)
         
     | 
| 
      
 154 
     | 
    
         
            +
                        add_offense(node.loc.name, message: MSG_NON_PREDICATE)
         
     | 
| 
      
 155 
     | 
    
         
            +
                      elsif !node.predicate_method? && all_return_values_boolean?(return_values)
         
     | 
| 
      
 156 
     | 
    
         
            +
                        add_offense(node.loc.name, message: MSG_PREDICATE)
         
     | 
| 
      
 157 
     | 
    
         
            +
                      end
         
     | 
| 
      
 158 
     | 
    
         
            +
                    end
         
     | 
| 
      
 159 
     | 
    
         
            +
                    alias on_defs on_def
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
                    private
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                    def allowed?(node)
         
     | 
| 
      
 164 
     | 
    
         
            +
                      node.method?(:initialize) ||
         
     | 
| 
      
 165 
     | 
    
         
            +
                        allowed_method?(node.method_name) ||
         
     | 
| 
      
 166 
     | 
    
         
            +
                        matches_allowed_pattern?(node.method_name) ||
         
     | 
| 
      
 167 
     | 
    
         
            +
                        allowed_bang_method?(node) ||
         
     | 
| 
      
 168 
     | 
    
         
            +
                        node.operator_method? ||
         
     | 
| 
      
 169 
     | 
    
         
            +
                        node.body.nil?
         
     | 
| 
      
 170 
     | 
    
         
            +
                    end
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                    def acceptable?(return_values)
         
     | 
| 
      
 173 
     | 
    
         
            +
                      # In `conservative` mode, if the method returns `super`, `zsuper`, or a
         
     | 
| 
      
 174 
     | 
    
         
            +
                      # non-comparison method call, the method name is acceptable.
         
     | 
| 
      
 175 
     | 
    
         
            +
                      return false unless conservative?
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
                      return_values.any? do |value|
         
     | 
| 
      
 178 
     | 
    
         
            +
                        value.type?(:super, :zsuper) || unknown_method_call?(value)
         
     | 
| 
      
 179 
     | 
    
         
            +
                      end
         
     | 
| 
      
 180 
     | 
    
         
            +
                    end
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
                    def unknown_method_call?(value)
         
     | 
| 
      
 183 
     | 
    
         
            +
                      return false unless value.call_type?
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                      !method_returning_boolean?(value)
         
     | 
| 
      
 186 
     | 
    
         
            +
                    end
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
                    def return_values(node)
         
     | 
| 
      
 189 
     | 
    
         
            +
                      # Collect all the (implicit and explicit) return values of a node
         
     | 
| 
      
 190 
     | 
    
         
            +
                      return_values = Set.new(node.begin_type? ? [] : [extract_return_value(node)])
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
                      node.each_descendant(:return) do |return_node|
         
     | 
| 
      
 193 
     | 
    
         
            +
                        return_values << extract_return_value(return_node)
         
     | 
| 
      
 194 
     | 
    
         
            +
                      end
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
                      return_values << last_value(node)
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                      process_return_values(return_values)
         
     | 
| 
      
 199 
     | 
    
         
            +
                    end
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
                    def all_return_values_boolean?(return_values)
         
     | 
| 
      
 202 
     | 
    
         
            +
                      values = return_values.reject { |value| value.type?(:super, :zsuper) }
         
     | 
| 
      
 203 
     | 
    
         
            +
                      return false if values.empty?
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
                      values.all? { |value| boolean_return?(value) }
         
     | 
| 
      
 206 
     | 
    
         
            +
                    end
         
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
                    def boolean_return?(value)
         
     | 
| 
      
 209 
     | 
    
         
            +
                      return true if value.boolean_type?
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                      method_returning_boolean?(value)
         
     | 
| 
      
 212 
     | 
    
         
            +
                    end
         
     | 
| 
      
 213 
     | 
    
         
            +
             
     | 
| 
      
 214 
     | 
    
         
            +
                    def method_returning_boolean?(value)
         
     | 
| 
      
 215 
     | 
    
         
            +
                      return false unless value.call_type?
         
     | 
| 
      
 216 
     | 
    
         
            +
                      return false if wayward_predicate?(value.method_name)
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
                      value.comparison_method? || value.predicate_method? || value.negation_method?
         
     | 
| 
      
 219 
     | 
    
         
            +
                    end
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                    def potential_non_predicate?(return_values)
         
     | 
| 
      
 222 
     | 
    
         
            +
                      # Assumes a method to be non-predicate if all return values are non-boolean literals.
         
     | 
| 
      
 223 
     | 
    
         
            +
                      #
         
     | 
| 
      
 224 
     | 
    
         
            +
                      # In `Mode: conservative`, if any of the return values is a boolean,
         
     | 
| 
      
 225 
     | 
    
         
            +
                      # the method name is acceptable.
         
     | 
| 
      
 226 
     | 
    
         
            +
                      # In `Mode: aggressive`, all return values must be booleans for a predicate
         
     | 
| 
      
 227 
     | 
    
         
            +
                      # method, or else an offense will be registered.
         
     | 
| 
      
 228 
     | 
    
         
            +
                      return false if conservative? && return_values.any? { |value| boolean_return?(value) }
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
                      return_values.any? do |value|
         
     | 
| 
      
 231 
     | 
    
         
            +
                        value.literal? && !value.boolean_type?
         
     | 
| 
      
 232 
     | 
    
         
            +
                      end
         
     | 
| 
      
 233 
     | 
    
         
            +
                    end
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
                    def extract_return_value(node)
         
     | 
| 
      
 236 
     | 
    
         
            +
                      return node unless node.return_type?
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
                      # `return` without a value is a `nil` return.
         
     | 
| 
      
 239 
     | 
    
         
            +
                      return s(:nil) if node.arguments.empty?
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
                      # When there's a multiple return, it cannot be a predicate
         
     | 
| 
      
 242 
     | 
    
         
            +
                      # so just return an `array` sexp for simplicity.
         
     | 
| 
      
 243 
     | 
    
         
            +
                      return s(:array) unless node.arguments.one?
         
     | 
| 
      
 244 
     | 
    
         
            +
             
     | 
| 
      
 245 
     | 
    
         
            +
                      node.first_argument
         
     | 
| 
      
 246 
     | 
    
         
            +
                    end
         
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
      
 248 
     | 
    
         
            +
                    def last_value(node)
         
     | 
| 
      
 249 
     | 
    
         
            +
                      value = node.begin_type? ? node.children.last || s(:nil) : node
         
     | 
| 
      
 250 
     | 
    
         
            +
             
     | 
| 
      
 251 
     | 
    
         
            +
                      value.return_type? ? extract_return_value(value) : value
         
     | 
| 
      
 252 
     | 
    
         
            +
                    end
         
     | 
| 
      
 253 
     | 
    
         
            +
             
     | 
| 
      
 254 
     | 
    
         
            +
                    def process_return_values(return_values)
         
     | 
| 
      
 255 
     | 
    
         
            +
                      return_values.flat_map do |value|
         
     | 
| 
      
 256 
     | 
    
         
            +
                        if value.conditional?
         
     | 
| 
      
 257 
     | 
    
         
            +
                          process_return_values(extract_conditional_branches(value))
         
     | 
| 
      
 258 
     | 
    
         
            +
                        elsif and_or?(value)
         
     | 
| 
      
 259 
     | 
    
         
            +
                          process_return_values(extract_and_or_clauses(value))
         
     | 
| 
      
 260 
     | 
    
         
            +
                        else
         
     | 
| 
      
 261 
     | 
    
         
            +
                          value
         
     | 
| 
      
 262 
     | 
    
         
            +
                        end
         
     | 
| 
      
 263 
     | 
    
         
            +
                      end
         
     | 
| 
      
 264 
     | 
    
         
            +
                    end
         
     | 
| 
      
 265 
     | 
    
         
            +
             
     | 
| 
      
 266 
     | 
    
         
            +
                    def and_or?(node)
         
     | 
| 
      
 267 
     | 
    
         
            +
                      node.type?(:and, :or)
         
     | 
| 
      
 268 
     | 
    
         
            +
                    end
         
     | 
| 
      
 269 
     | 
    
         
            +
             
     | 
| 
      
 270 
     | 
    
         
            +
                    def extract_and_or_clauses(node)
         
     | 
| 
      
 271 
     | 
    
         
            +
                      # Recursively traverse an `and` or `or` node to collect all clauses within
         
     | 
| 
      
 272 
     | 
    
         
            +
                      return node unless and_or?(node)
         
     | 
| 
      
 273 
     | 
    
         
            +
             
     | 
| 
      
 274 
     | 
    
         
            +
                      [extract_and_or_clauses(node.lhs), extract_and_or_clauses(node.rhs)].flatten
         
     | 
| 
      
 275 
     | 
    
         
            +
                    end
         
     | 
| 
      
 276 
     | 
    
         
            +
             
     | 
| 
      
 277 
     | 
    
         
            +
                    def extract_conditional_branches(node)
         
     | 
| 
      
 278 
     | 
    
         
            +
                      return node unless node.conditional?
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
                      if node.type?(:while, :until)
         
     | 
| 
      
 281 
     | 
    
         
            +
                        # If there is no body, act as implicit `nil`.
         
     | 
| 
      
 282 
     | 
    
         
            +
                        node.body ? [last_value(node.body)] : [s(:nil)]
         
     | 
| 
      
 283 
     | 
    
         
            +
                      else
         
     | 
| 
      
 284 
     | 
    
         
            +
                        # Branches with no value act as an implicit `nil`.
         
     | 
| 
      
 285 
     | 
    
         
            +
                        branches = node.branches.map { |branch| branch ? last_value(branch) : s(:nil) }
         
     | 
| 
      
 286 
     | 
    
         
            +
                        # Missing else branches also act as an implicit `nil`.
         
     | 
| 
      
 287 
     | 
    
         
            +
                        branches.push(s(:nil)) unless node.else_branch
         
     | 
| 
      
 288 
     | 
    
         
            +
                        branches
         
     | 
| 
      
 289 
     | 
    
         
            +
                      end
         
     | 
| 
      
 290 
     | 
    
         
            +
                    end
         
     | 
| 
      
 291 
     | 
    
         
            +
             
     | 
| 
      
 292 
     | 
    
         
            +
                    def conservative?
         
     | 
| 
      
 293 
     | 
    
         
            +
                      cop_config.fetch('Mode', :conservative).to_sym == :conservative
         
     | 
| 
      
 294 
     | 
    
         
            +
                    end
         
     | 
| 
      
 295 
     | 
    
         
            +
             
     | 
| 
      
 296 
     | 
    
         
            +
                    def allowed_bang_method?(node)
         
     | 
| 
      
 297 
     | 
    
         
            +
                      return false unless allow_bang_methods?
         
     | 
| 
      
 298 
     | 
    
         
            +
             
     | 
| 
      
 299 
     | 
    
         
            +
                      node.bang_method?
         
     | 
| 
      
 300 
     | 
    
         
            +
                    end
         
     | 
| 
      
 301 
     | 
    
         
            +
             
     | 
| 
      
 302 
     | 
    
         
            +
                    def allow_bang_methods?
         
     | 
| 
      
 303 
     | 
    
         
            +
                      cop_config.fetch('AllowBangMethods', false)
         
     | 
| 
      
 304 
     | 
    
         
            +
                    end
         
     | 
| 
      
 305 
     | 
    
         
            +
             
     | 
| 
      
 306 
     | 
    
         
            +
                    # If a method ending in `?` is known to not return a boolean value,
         
     | 
| 
      
 307 
     | 
    
         
            +
                    # (for example, `Numeric#nonzero?`) it should be treated as a non-boolean
         
     | 
| 
      
 308 
     | 
    
         
            +
                    # value, despite the method naming.
         
     | 
| 
      
 309 
     | 
    
         
            +
                    def wayward_predicate?(name)
         
     | 
| 
      
 310 
     | 
    
         
            +
                      wayward_predicates.include?(name.to_s)
         
     | 
| 
      
 311 
     | 
    
         
            +
                    end
         
     | 
| 
      
 312 
     | 
    
         
            +
             
     | 
| 
      
 313 
     | 
    
         
            +
                    def wayward_predicates
         
     | 
| 
      
 314 
     | 
    
         
            +
                      Array(cop_config.fetch('WaywardPredicates', []))
         
     | 
| 
      
 315 
     | 
    
         
            +
                    end
         
     | 
| 
      
 316 
     | 
    
         
            +
                  end
         
     | 
| 
      
 317 
     | 
    
         
            +
                end
         
     | 
| 
      
 318 
     | 
    
         
            +
              end
         
     | 
| 
      
 319 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -100,12 +100,12 @@ module RuboCop 
     | 
|
| 
       100 
100 
     | 
    
         
             
                  #   # good
         
     | 
| 
       101 
101 
     | 
    
         
             
                  #   def_node_matcher(:even?) { |value| }
         
     | 
| 
       102 
102 
     | 
    
         
             
                  #
         
     | 
| 
       103 
     | 
    
         
            -
                  class  
     | 
| 
      
 103 
     | 
    
         
            +
                  class PredicatePrefix < Base
         
     | 
| 
       104 
104 
     | 
    
         
             
                    include AllowedMethods
         
     | 
| 
       105 
105 
     | 
    
         | 
| 
       106 
106 
     | 
    
         
             
                    # @!method dynamic_method_define(node)
         
     | 
| 
       107 
107 
     | 
    
         
             
                    def_node_matcher :dynamic_method_define, <<~PATTERN
         
     | 
| 
       108 
     | 
    
         
            -
                      (send nil? # 
     | 
| 
      
 108 
     | 
    
         
            +
                      (send nil? #method_definition_macro?
         
     | 
| 
       109 
109 
     | 
    
         
             
                        (sym $_)
         
     | 
| 
       110 
110 
     | 
    
         
             
                        ...)
         
     | 
| 
       111 
111 
     | 
    
         
             
                    PATTERN
         
     | 
| 
         @@ -143,7 +143,7 @@ module RuboCop 
     | 
|
| 
       143 
143 
     | 
    
         
             
                        next if predicate_prefixes.include?(forbidden_prefix)
         
     | 
| 
       144 
144 
     | 
    
         | 
| 
       145 
145 
     | 
    
         
             
                        raise ValidationError, <<~MSG.chomp
         
     | 
| 
       146 
     | 
    
         
            -
                          The `Naming/ 
     | 
| 
      
 146 
     | 
    
         
            +
                          The `Naming/PredicatePrefix` cop is misconfigured. Prefix #{forbidden_prefix} must be included in NamePrefix because it is included in ForbiddenPrefixes.
         
     | 
| 
       147 
147 
     | 
    
         
             
                        MSG
         
     | 
| 
       148 
148 
     | 
    
         
             
                      end
         
     | 
| 
       149 
149 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -195,7 +195,7 @@ module RuboCop 
     | 
|
| 
       195 
195 
     | 
    
         
             
                      cop_config['UseSorbetSigs']
         
     | 
| 
       196 
196 
     | 
    
         
             
                    end
         
     | 
| 
       197 
197 
     | 
    
         | 
| 
       198 
     | 
    
         
            -
                    def  
     | 
| 
      
 198 
     | 
    
         
            +
                    def method_definition_macro?(macro_name)
         
     | 
| 
       199 
199 
     | 
    
         
             
                      cop_config['MethodDefinitionMacros'].include?(macro_name.to_s)
         
     | 
| 
       200 
200 
     | 
    
         
             
                    end
         
     | 
| 
       201 
201 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -11,13 +11,14 @@ module RuboCop 
     | 
|
| 
       11 
11 
     | 
    
         
             
                  #
         
     | 
| 
       12 
12 
     | 
    
         
             
                  #   eval(something)
         
     | 
| 
       13 
13 
     | 
    
         
             
                  #   binding.eval(something)
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #   Kernel.eval(something)
         
     | 
| 
       14 
15 
     | 
    
         
             
                  class Eval < Base
         
     | 
| 
       15 
16 
     | 
    
         
             
                    MSG = 'The use of `eval` is a serious security risk.'
         
     | 
| 
       16 
17 
     | 
    
         
             
                    RESTRICT_ON_SEND = %i[eval].freeze
         
     | 
| 
       17 
18 
     | 
    
         | 
| 
       18 
19 
     | 
    
         
             
                    # @!method eval?(node)
         
     | 
| 
       19 
20 
     | 
    
         
             
                    def_node_matcher :eval?, <<~PATTERN
         
     | 
| 
       20 
     | 
    
         
            -
                      (send {nil? (send nil? :binding)} :eval $!str ...)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      (send {nil? (send nil? :binding) (const {cbase nil?} :Kernel)} :eval $!str ...)
         
     | 
| 
       21 
22 
     | 
    
         
             
                    PATTERN
         
     | 
| 
       22 
23 
     | 
    
         | 
| 
       23 
24 
     | 
    
         
             
                    def on_send(node)
         
     |