rubocop 1.75.8 → 1.79.1

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.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -16
  3. data/config/default.yml +107 -26
  4. data/config/obsoletion.yml +6 -3
  5. data/lib/rubocop/cli.rb +12 -1
  6. data/lib/rubocop/config_loader.rb +1 -38
  7. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  8. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
  9. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  10. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
  11. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  12. data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
  13. data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
  14. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
  15. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +1 -0
  16. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
  17. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  18. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
  19. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +99 -0
  20. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -1
  21. data/lib/rubocop/cop/layout/line_length.rb +26 -5
  22. data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
  23. data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
  24. data/lib/rubocop/cop/layout/space_before_brackets.rb +2 -9
  25. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
  26. data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
  27. data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
  28. data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
  29. data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
  30. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  31. data/lib/rubocop/cop/lint/literal_as_condition.rb +34 -28
  32. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
  33. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  34. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
  35. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
  36. data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
  37. data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
  38. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
  39. data/lib/rubocop/cop/lint/self_assignment.rb +25 -0
  40. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
  41. data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
  42. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
  43. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
  44. data/lib/rubocop/cop/lint/useless_or.rb +98 -0
  45. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
  46. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
  47. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  48. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  49. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  50. data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
  51. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  52. data/lib/rubocop/cop/naming/file_name.rb +2 -2
  53. data/lib/rubocop/cop/naming/method_name.rb +127 -13
  54. data/lib/rubocop/cop/naming/predicate_method.rb +306 -0
  55. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
  56. data/lib/rubocop/cop/security/eval.rb +2 -1
  57. data/lib/rubocop/cop/security/open.rb +1 -0
  58. data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
  59. data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
  60. data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
  61. data/lib/rubocop/cop/style/array_intersect.rb +53 -23
  62. data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
  63. data/lib/rubocop/cop/style/case_like_if.rb +1 -1
  64. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  65. data/lib/rubocop/cop/style/conditional_assignment.rb +4 -2
  66. data/lib/rubocop/cop/style/dig_chain.rb +1 -1
  67. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
  68. data/lib/rubocop/cop/style/exponential_notation.rb +3 -2
  69. data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
  70. data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
  71. data/lib/rubocop/cop/style/if_unless_modifier.rb +13 -6
  72. data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
  73. data/lib/rubocop/cop/style/it_assignment.rb +69 -12
  74. data/lib/rubocop/cop/style/it_block_parameter.rb +36 -15
  75. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -6
  76. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
  77. data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
  78. data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
  79. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  80. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
  81. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  82. data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
  83. data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
  84. data/lib/rubocop/cop/style/redundant_parentheses.rb +35 -5
  85. data/lib/rubocop/cop/style/redundant_self.rb +8 -5
  86. data/lib/rubocop/cop/style/safe_navigation.rb +24 -11
  87. data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
  88. data/lib/rubocop/cop/style/sole_nested_conditional.rb +32 -2
  89. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
  90. data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
  91. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  92. data/lib/rubocop/cop/variable_force.rb +18 -7
  93. data/lib/rubocop/cops_documentation_generator.rb +1 -0
  94. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  95. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  96. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
  97. data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
  98. data/lib/rubocop/lsp/diagnostic.rb +4 -4
  99. data/lib/rubocop/lsp/routes.rb +4 -4
  100. data/lib/rubocop/pending_cops_reporter.rb +56 -0
  101. data/lib/rubocop/rspec/expect_offense.rb +9 -3
  102. data/lib/rubocop/server/cache.rb +4 -2
  103. data/lib/rubocop/server/client_command/base.rb +10 -0
  104. data/lib/rubocop/server/client_command/exec.rb +2 -1
  105. data/lib/rubocop/server/client_command/start.rb +11 -1
  106. data/lib/rubocop/version.rb +1 -1
  107. data/lib/rubocop.rb +11 -1
  108. data/lib/ruby_lsp/rubocop/addon.rb +2 -2
  109. metadata +21 -8
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for useless OR (`||` and `or`) expressions.
7
+ #
8
+ # Some methods always return a truthy value, even when called
9
+ # on `nil` (e.g. `nil.to_i` evaluates to `0`). Therefore, OR expressions
10
+ # appended after these methods will never evaluate.
11
+ #
12
+ # @example
13
+ #
14
+ # # bad
15
+ # x.to_a || fallback
16
+ # x.to_c || fallback
17
+ # x.to_d || fallback
18
+ # x.to_i || fallback
19
+ # x.to_f || fallback
20
+ # x.to_h || fallback
21
+ # x.to_r || fallback
22
+ # x.to_s || fallback
23
+ # x.to_sym || fallback
24
+ # x.intern || fallback
25
+ # x.inspect || fallback
26
+ # x.hash || fallback
27
+ # x.object_id || fallback
28
+ # x.__id__ || fallback
29
+ #
30
+ # x.to_s or fallback
31
+ #
32
+ # # good - if fallback is same as return value of method called on nil
33
+ # x.to_a # nil.to_a returns []
34
+ # x.to_c # nil.to_c returns (0+0i)
35
+ # x.to_d # nil.to_d returns 0.0
36
+ # x.to_i # nil.to_i returns 0
37
+ # x.to_f # nil.to_f returns 0.0
38
+ # x.to_h # nil.to_h returns {}
39
+ # x.to_r # nil.to_r returns (0/1)
40
+ # x.to_s # nil.to_s returns ''
41
+ # x.to_sym # nil.to_sym raises an error
42
+ # x.intern # nil.intern raises an error
43
+ # x.inspect # nil.inspect returns "nil"
44
+ # x.hash # nil.hash returns an Integer
45
+ # x.object_id # nil.object_id returns an Integer
46
+ # x.__id__ # nil.object_id returns an Integer
47
+ #
48
+ # # good - if the intention is not to call the method on nil
49
+ # x&.to_a || fallback
50
+ # x&.to_c || fallback
51
+ # x&.to_d || fallback
52
+ # x&.to_i || fallback
53
+ # x&.to_f || fallback
54
+ # x&.to_h || fallback
55
+ # x&.to_r || fallback
56
+ # x&.to_s || fallback
57
+ # x&.to_sym || fallback
58
+ # x&.intern || fallback
59
+ # x&.inspect || fallback
60
+ # x&.hash || fallback
61
+ # x&.object_id || fallback
62
+ # x&.__id__ || fallback
63
+ #
64
+ # x&.to_s or fallback
65
+ #
66
+ class UselessOr < Base
67
+ MSG = '`%<rhs>s` will never evaluate because `%<lhs>s` always returns a truthy value.'
68
+
69
+ TRUTHY_RETURN_VALUE_METHODS = Set[:to_a, :to_c, :to_d, :to_i, :to_f, :to_h, :to_r,
70
+ :to_s, :to_sym, :intern, :inspect, :hash, :object_id,
71
+ :__id__].freeze
72
+
73
+ # @!method truthy_return_value_method?(node)
74
+ def_node_matcher :truthy_return_value_method?, <<~PATTERN
75
+ (send _ %TRUTHY_RETURN_VALUE_METHODS)
76
+ PATTERN
77
+
78
+ def on_or(node)
79
+ if truthy_return_value_method?(node.lhs)
80
+ report_offense(node, node.lhs)
81
+ elsif truthy_return_value_method?(node.rhs)
82
+ parent = node.parent
83
+ parent = parent.parent if parent&.begin_type?
84
+
85
+ report_offense(parent, node.rhs) if parent&.or_type?
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def report_offense(or_node, truthy_node)
92
+ add_offense(or_node.loc.operator.join(or_node.rhs.source_range),
93
+ message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source))
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -89,7 +89,7 @@ module RuboCop
89
89
  private
90
90
 
91
91
  def inspect_def(node, def_node)
92
- return if allowed_arguments(def_node.arguments)
92
+ return if allowed_arguments?(def_node.arguments)
93
93
 
94
94
  add_offense(node.loc.selector, message: format(MSG, method_name: def_node.method_name))
95
95
  end
@@ -101,7 +101,7 @@ module RuboCop
101
101
  definition = find_method_definition(node, method_name)
102
102
 
103
103
  return unless definition
104
- return if allowed_arguments(definition.arguments)
104
+ return if allowed_arguments?(definition.arguments)
105
105
 
106
106
  add_offense(node, message: format(MSG, method_name: method_name))
107
107
  end
@@ -115,7 +115,7 @@ module RuboCop
115
115
  end
116
116
 
117
117
  # `ruby2_keywords` is only allowed if there's a `restarg` and no keyword arguments
118
- def allowed_arguments(arguments)
118
+ def allowed_arguments?(arguments)
119
119
  return false if arguments.empty?
120
120
 
121
121
  arguments.each_child_node(:restarg).any? &&
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ module Utils
7
+ # Utility class that checks if the receiver can't be nil.
8
+ class NilReceiverChecker
9
+ NIL_METHODS = (nil.methods + %i[!]).to_set.freeze
10
+
11
+ def initialize(receiver, additional_nil_methods)
12
+ @receiver = receiver
13
+ @additional_nil_methods = additional_nil_methods
14
+ @checked_nodes = {}.compare_by_identity
15
+ end
16
+
17
+ def cant_be_nil?
18
+ sole_condition_of_parent_if?(@receiver) || _cant_be_nil?(@receiver.parent, @receiver)
19
+ end
20
+
21
+ private
22
+
23
+ # rubocop:disable Metrics
24
+ def _cant_be_nil?(node, receiver)
25
+ return false unless node
26
+
27
+ # For some nodes, we check their parent and then some children for these parents.
28
+ # This is added to avoid infinite loops.
29
+ return false if @checked_nodes.key?(node)
30
+
31
+ @checked_nodes[node] = true
32
+
33
+ case node.type
34
+ when :def, :class, :module, :sclass
35
+ return false
36
+ when :send
37
+ return non_nil_method?(node.method_name) if node.receiver == receiver
38
+
39
+ node.arguments.each do |argument|
40
+ return true if _cant_be_nil?(argument, receiver)
41
+ end
42
+
43
+ return true if _cant_be_nil?(node.receiver, receiver)
44
+ when :begin
45
+ return true if _cant_be_nil?(node.children.first, receiver)
46
+ when :if, :case
47
+ return true if _cant_be_nil?(node.condition, receiver)
48
+ when :and, :or
49
+ return true if _cant_be_nil?(node.lhs, receiver)
50
+ when :pair
51
+ if _cant_be_nil?(node.key, receiver) ||
52
+ _cant_be_nil?(node.value, receiver)
53
+ return true
54
+ end
55
+ when :when
56
+ node.each_condition do |condition|
57
+ return true if _cant_be_nil?(condition, receiver)
58
+ end
59
+ when :lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn
60
+ return true if _cant_be_nil?(node.expression, receiver)
61
+ end
62
+
63
+ # Due to how `if/else` are implemented (`elsif` is a child of `if` or another `elsif`),
64
+ # using left_siblings will not work correctly for them.
65
+ if !else_branch?(node) || (node.if_type? && !node.elsif?)
66
+ node.left_siblings.reverse_each do |sibling|
67
+ next unless sibling.is_a?(AST::Node)
68
+
69
+ return true if _cant_be_nil?(sibling, receiver)
70
+ end
71
+ end
72
+
73
+ if node.parent
74
+ _cant_be_nil?(node.parent, receiver)
75
+ else
76
+ false
77
+ end
78
+ end
79
+ # rubocop:enable Metrics
80
+
81
+ def non_nil_method?(method_name)
82
+ !NIL_METHODS.include?(method_name) && !@additional_nil_methods.include?(method_name)
83
+ end
84
+
85
+ # rubocop:disable Metrics/PerceivedComplexity
86
+ def sole_condition_of_parent_if?(node)
87
+ parent = node.parent
88
+
89
+ while parent
90
+ if parent.if_type?
91
+ if parent.condition == node
92
+ return true
93
+ elsif parent.elsif?
94
+ parent = find_top_if(parent)
95
+ end
96
+ elsif else_branch?(parent)
97
+ # Find the top `if` for `else`.
98
+ parent = parent.parent
99
+ end
100
+
101
+ parent = parent&.parent
102
+ end
103
+
104
+ false
105
+ end
106
+ # rubocop:enable Metrics/PerceivedComplexity
107
+
108
+ def else_branch?(node)
109
+ node.parent&.if_type? && node.parent.else_branch == node
110
+ end
111
+
112
+ def find_top_if(node)
113
+ node = node.parent while node.elsif?
114
+
115
+ node
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -66,7 +66,7 @@ module RuboCop
66
66
  end
67
67
 
68
68
  # @deprecated Use processed_source.line_with_comment?(line)
69
- def end_of_line_comment(line)
69
+ def end_of_line_comment(line) # rubocop:disable Naming/PredicateMethod
70
70
  warn Rainbow(<<~WARNING).yellow, uplevel: 1
71
71
  `end_of_line_comment` is deprecated. Use `processed_source.line_with_comment?` instead.
72
72
  WARNING
@@ -89,7 +89,7 @@ module RuboCop
89
89
 
90
90
  if first_non_comment_token
91
91
  # `line` is 1-indexed so we need to subtract 1 to get the array index
92
- processed_source.lines[0...first_non_comment_token.line - 1]
92
+ processed_source.lines[0...(first_non_comment_token.line - 1)]
93
93
  else
94
94
  processed_source.lines
95
95
  end
@@ -25,6 +25,28 @@ module RuboCop
25
25
  (args
26
26
  (arg $_)) ...)
27
27
  PATTERN
28
+
29
+ # @!method assignment_method_declarations(node)
30
+ def_node_search :assignment_method_declarations, <<~PATTERN
31
+ (send
32
+ (lvar {#match_block_variable_name? :_1 :it}) _ ...)
33
+ PATTERN
34
+
35
+ # @!method indexed_assignment_method_declarations(node)
36
+ def_node_search :indexed_assignment_method_declarations, <<~PATTERN
37
+ (send
38
+ (send (lvar {#match_block_variable_name? :_1 :it}) _)
39
+ :[]=
40
+ literal?
41
+ _
42
+ )
43
+ PATTERN
44
+
45
+ def match_block_variable_name?(receiver_name)
46
+ gem_specification(processed_source.ast) do |block_variable_name|
47
+ return block_variable_name == receiver_name
48
+ end
49
+ end
28
50
  end
29
51
  end
30
52
  end
@@ -25,20 +25,24 @@ module RuboCop
25
25
  config.for_cop('Layout/LineLength')['AllowURI']
26
26
  end
27
27
 
28
- def allowed_uri_position?(line, uri_range)
29
- uri_range.begin < max_line_length && uri_range.end == line_length(line)
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 find_excessive_uri_range(line)
37
- last_uri_match = match_uris(line).last
38
- return nil unless last_uri_match
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 = last_uri_match.offset(0)
41
- end_position = extend_uri_end_position(line, 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 extend_uri_end_position(line, end_position)
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
@@ -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? || match_namespace(child, const_namespace, namespace)
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 match_namespace(node, namespace, expected)
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,79 @@ 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
+ handle_method_name(node.new_identifier, node.new_identifier.value)
151
+ end
152
+
153
+ private
154
+
155
+ def handle_define_method(node)
156
+ return unless node.first_argument&.type?(:str, :sym)
157
+
158
+ handle_method_name(node, node.first_argument.value)
159
+ end
160
+
161
+ def handle_new_struct(node)
162
+ arguments = node.first_argument&.str_type? ? node.arguments[1..] : node.arguments
163
+ arguments.select { |argument| argument.type?(:sym, :str) }.each do |name|
164
+ handle_method_name(name, name.value)
165
+ end
166
+ end
167
+
168
+ def handle_define_data(node)
169
+ node.arguments.select { |argument| argument.type?(:sym, :str) }.each do |name|
170
+ handle_method_name(name, name.value)
171
+ end
172
+ end
173
+
174
+ def handle_alias_method(node)
175
+ return unless node.arguments.size == 2
176
+ return unless node.first_argument.type?(:str, :sym)
177
+
178
+ handle_method_name(node.first_argument, node.first_argument.value)
179
+ end
180
+
181
+ def handle_attr_accessor(node)
76
182
  return unless (attrs = node.attribute_accessor?)
77
183
 
78
184
  attrs.last.each do |name_item|
@@ -87,45 +193,53 @@ module RuboCop
87
193
  end
88
194
  end
89
195
 
90
- def on_def(node)
91
- return if node.operator_method? || matches_allowed_pattern?(node.method_name)
196
+ def handle_method_name(node, name)
197
+ return if !name || matches_allowed_pattern?(name)
92
198
 
93
- if forbidden_name?(node.method_name.to_s)
199
+ if forbidden_name?(name.to_s)
94
200
  register_forbidden_name(node)
95
- else
96
- check_name(node, node.method_name, node.loc.name)
201
+ elsif !OPERATOR_METHODS.include?(name)
202
+ check_name(node, name, range_position(node))
97
203
  end
98
204
  end
99
- alias on_defs on_def
100
-
101
- private
102
205
 
103
206
  def forbidden_name?(name)
104
207
  forbidden_identifier?(name) || forbidden_pattern?(name)
105
208
  end
106
209
 
210
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
107
211
  def register_forbidden_name(node)
108
212
  if node.any_def_type?
109
213
  name_node = node.loc.name
110
214
  method_name = node.method_name
111
- else
112
- attrs = node.attribute_accessor?
215
+ elsif node.literal?
216
+ name_node = node
217
+ method_name = node.value
218
+ elsif (attrs = node.attribute_accessor?)
113
219
  name_node = attrs.last.last
114
220
  method_name = attr_name(name_node)
221
+ else
222
+ name_node = node.first_argument
223
+ method_name = node.first_argument.value
115
224
  end
116
225
  message = format(MSG_FORBIDDEN, identifier: method_name)
117
226
  add_offense(name_node, message: message)
118
227
  end
228
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
119
229
 
120
230
  def attr_name(name_item)
121
231
  sym_name(name_item) || str_name(name_item)
122
232
  end
123
233
 
124
234
  def range_position(node)
125
- selector_end_pos = node.loc.selector.end_pos + 1
126
- expr_end_pos = node.source_range.end_pos
235
+ if node.loc.respond_to?(:selector)
236
+ selector_end_pos = node.loc.selector.end_pos + 1
237
+ expr_end_pos = node.source_range.end_pos
127
238
 
128
- range_between(selector_end_pos, expr_end_pos)
239
+ range_between(selector_end_pos, expr_end_pos)
240
+ else
241
+ node.source_range
242
+ end
129
243
  end
130
244
 
131
245
  def message(style)