rubocop-performance 1.13.3 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +13 -2
  5. data/lib/rubocop/cop/mixin/regexp_metacharacter.rb +2 -2
  6. data/lib/rubocop/cop/mixin/sort_block.rb +7 -0
  7. data/lib/rubocop/cop/performance/ancestors_include.rb +1 -2
  8. data/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb +3 -2
  9. data/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +2 -6
  10. data/lib/rubocop/cop/performance/bind_call.rb +1 -2
  11. data/lib/rubocop/cop/performance/block_given_with_explicit_block.rb +1 -1
  12. data/lib/rubocop/cop/performance/caller.rb +1 -2
  13. data/lib/rubocop/cop/performance/case_when_splat.rb +7 -13
  14. data/lib/rubocop/cop/performance/casecmp.rb +10 -12
  15. data/lib/rubocop/cop/performance/chain_array_allocation.rb +5 -5
  16. data/lib/rubocop/cop/performance/collection_literal_in_loop.rb +4 -6
  17. data/lib/rubocop/cop/performance/compare_with_block.rb +20 -11
  18. data/lib/rubocop/cop/performance/concurrent_monotonic_time.rb +1 -1
  19. data/lib/rubocop/cop/performance/constant_regexp.rb +6 -4
  20. data/lib/rubocop/cop/performance/count.rb +39 -3
  21. data/lib/rubocop/cop/performance/delete_prefix.rb +8 -2
  22. data/lib/rubocop/cop/performance/delete_suffix.rb +8 -2
  23. data/lib/rubocop/cop/performance/detect.rb +7 -6
  24. data/lib/rubocop/cop/performance/double_start_end_with.rb +4 -5
  25. data/lib/rubocop/cop/performance/end_with.rb +7 -6
  26. data/lib/rubocop/cop/performance/fixed_size.rb +2 -2
  27. data/lib/rubocop/cop/performance/flat_map.rb +7 -5
  28. data/lib/rubocop/cop/performance/inefficient_hash_search.rb +17 -15
  29. data/lib/rubocop/cop/performance/io_readlines.rb +2 -2
  30. data/lib/rubocop/cop/performance/map_compact.rb +9 -4
  31. data/lib/rubocop/cop/performance/map_method_chain.rb +87 -0
  32. data/lib/rubocop/cop/performance/method_object_as_block.rb +1 -1
  33. data/lib/rubocop/cop/performance/open_struct.rb +2 -3
  34. data/lib/rubocop/cop/performance/range_include.rb +2 -2
  35. data/lib/rubocop/cop/performance/redundant_block_call.rb +2 -2
  36. data/lib/rubocop/cop/performance/redundant_equality_comparison_block.rb +38 -3
  37. data/lib/rubocop/cop/performance/redundant_match.rb +10 -9
  38. data/lib/rubocop/cop/performance/redundant_merge.rb +9 -16
  39. data/lib/rubocop/cop/performance/redundant_sort_block.rb +17 -10
  40. data/lib/rubocop/cop/performance/redundant_split_regexp_argument.rb +3 -2
  41. data/lib/rubocop/cop/performance/redundant_string_chars.rb +10 -6
  42. data/lib/rubocop/cop/performance/regexp_match.rb +23 -24
  43. data/lib/rubocop/cop/performance/reverse_each.rb +3 -3
  44. data/lib/rubocop/cop/performance/reverse_first.rb +4 -3
  45. data/lib/rubocop/cop/performance/select_map.rb +2 -1
  46. data/lib/rubocop/cop/performance/size.rb +1 -2
  47. data/lib/rubocop/cop/performance/sort_reverse.rb +19 -10
  48. data/lib/rubocop/cop/performance/squeeze.rb +8 -8
  49. data/lib/rubocop/cop/performance/start_with.rb +7 -6
  50. data/lib/rubocop/cop/performance/string_identifier_argument.rb +16 -11
  51. data/lib/rubocop/cop/performance/string_include.rb +23 -17
  52. data/lib/rubocop/cop/performance/string_replacement.rb +7 -10
  53. data/lib/rubocop/cop/performance/sum.rb +7 -4
  54. data/lib/rubocop/cop/performance/times_map.rb +6 -7
  55. data/lib/rubocop/cop/performance/uri_default_parser.rb +4 -6
  56. data/lib/rubocop/cop/performance_cops.rb +1 -0
  57. data/lib/rubocop/performance/version.rb +1 -1
  58. metadata +6 -5
@@ -3,8 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # This cop identifies places where `Hash#merge!` can be replaced by
7
- # `Hash#[]=`.
6
+ # Identifies places where `Hash#merge!` can be replaced by `Hash#[]=`.
8
7
  # You can set the maximum number of key-value pairs to consider
9
8
  # an offense with `MaxKeyValuePairs`.
10
9
  #
@@ -29,6 +28,7 @@ module RuboCop
29
28
  # hash[:a] = 1
30
29
  # hash[:b] = 2
31
30
  class RedundantMerge < Base
31
+ include Alignment
32
32
  extend AutoCorrector
33
33
 
34
34
  AREF_ASGN = '%<receiver>s[%<key>s] = %<value>s'
@@ -100,8 +100,7 @@ module RuboCop
100
100
  end
101
101
 
102
102
  def non_redundant_value_used?(receiver, node)
103
- node.value_used? &&
104
- !EachWithObjectInspector.new(node, receiver).value_used?
103
+ node.value_used? && !EachWithObjectInspector.new(node, receiver).value_used?
105
104
  end
106
105
 
107
106
  def correct_multiple_elements(corrector, node, parent, new_source)
@@ -110,14 +109,14 @@ module RuboCop
110
109
  node = parent
111
110
  else
112
111
  padding = "\n#{leading_spaces(node)}"
113
- new_source.gsub!(/\n/, padding)
112
+ new_source.gsub!("\n", padding)
114
113
  end
115
114
 
116
- corrector.replace(node.source_range, new_source)
115
+ corrector.replace(node, new_source)
117
116
  end
118
117
 
119
118
  def correct_single_element(corrector, node, new_source)
120
- corrector.replace(node.source_range, new_source)
119
+ corrector.replace(node, new_source)
121
120
  end
122
121
 
123
122
  def to_assignments(receiver, pairs)
@@ -126,16 +125,14 @@ module RuboCop
126
125
 
127
126
  key = key.sym_type? && pair.colon? ? ":#{key.source}" : key.source
128
127
 
129
- format(AREF_ASGN, receiver: receiver.source,
130
- key: key,
131
- value: value.source)
128
+ format(AREF_ASGN, receiver: receiver.source, key: key, value: value.source)
132
129
  end
133
130
  end
134
131
 
135
132
  def rewrite_with_modifier(node, parent, new_source)
136
- indent = ' ' * indent_width
133
+ indent = ' ' * configured_indentation_width
137
134
  padding = "\n#{indent + leading_spaces(node)}"
138
- new_source.gsub!(/\n/, padding)
135
+ new_source.gsub!("\n", padding)
139
136
 
140
137
  format(WITH_MODIFIER_CORRECTION, keyword: parent.loc.keyword.source,
141
138
  condition: parent.condition.source,
@@ -148,10 +145,6 @@ module RuboCop
148
145
  node.source_range.source_line[/\A\s*/]
149
146
  end
150
147
 
151
- def indent_width
152
- @config.for_cop('Layout/IndentationWidth')['Width'] || 2
153
- end
154
-
155
148
  def max_key_value_pairs
156
149
  Integer(cop_config['MaxKeyValuePairs'] || 2)
157
150
  end
@@ -3,8 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # This cop identifies places where `sort { |a, b| a <=> b }`
7
- # can be replaced with `sort`.
6
+ # Identifies places where `sort { |a, b| a <=> b }` can be replaced with `sort`.
8
7
  #
9
8
  # @example
10
9
  # # bad
@@ -17,25 +16,33 @@ module RuboCop
17
16
  include SortBlock
18
17
  extend AutoCorrector
19
18
 
20
- MSG = 'Use `sort` instead of `%<bad_method>s`.'
19
+ MSG = 'Use `sort` without block.'
21
20
 
22
21
  def on_block(node)
23
22
  return unless (send, var_a, var_b, body = sort_with_block?(node))
24
23
 
25
24
  replaceable_body?(body, var_a, var_b) do
26
- range = sort_range(send, node)
25
+ register_offense(send, node)
26
+ end
27
+ end
28
+
29
+ def on_numblock(node)
30
+ return unless (send, arg_count, body = sort_with_numblock?(node))
31
+ return unless arg_count == 2
27
32
 
28
- add_offense(range, message: message(var_a, var_b)) do |corrector|
29
- corrector.replace(range, 'sort')
30
- end
33
+ replaceable_body?(body, :_1, :_2) do
34
+ register_offense(send, node)
31
35
  end
32
36
  end
33
37
 
34
38
  private
35
39
 
36
- def message(var_a, var_b)
37
- bad_method = "sort { |#{var_a}, #{var_b}| #{var_a} <=> #{var_b} }"
38
- format(MSG, bad_method: bad_method)
40
+ def register_offense(send, node)
41
+ range = sort_range(send, node)
42
+
43
+ add_offense(range) do |corrector|
44
+ corrector.replace(range, 'sort')
45
+ end
39
46
  end
40
47
  end
41
48
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # This cop identifies places where `split` argument can be replaced from
6
+ # Identifies places where `split` argument can be replaced from
7
7
  # a deterministic regexp to a string.
8
8
  #
9
9
  # @example
@@ -21,7 +21,7 @@ module RuboCop
21
21
  STR_SPECIAL_CHARS = %w[\n \" \' \\\\ \t \b \f \r].freeze
22
22
 
23
23
  def_node_matcher :split_call_with_regexp?, <<~PATTERN
24
- {(send !nil? :split $regexp)}
24
+ {(call !nil? :split $regexp)}
25
25
  PATTERN
26
26
 
27
27
  def on_send(node)
@@ -35,6 +35,7 @@ module RuboCop
35
35
  corrector.replace(regexp_node, "\"#{new_argument}\"")
36
36
  end
37
37
  end
38
+ alias on_csend on_send
38
39
 
39
40
  private
40
41
 
@@ -3,12 +3,13 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # This cop checks for redundant `String#chars`.
6
+ # Checks for redundant `String#chars`.
7
7
  #
8
8
  # @example
9
9
  # # bad
10
10
  # str.chars[0..2]
11
11
  # str.chars.slice(0..2)
12
+ # str.chars.last
12
13
  #
13
14
  # # good
14
15
  # str[0..2].chars
@@ -20,6 +21,7 @@ module RuboCop
20
21
  # # good
21
22
  # str[0]
22
23
  # str[0...2].chars
24
+ # str[-1]
23
25
  #
24
26
  # # bad
25
27
  # str.chars.take(2)
@@ -33,9 +35,8 @@ module RuboCop
33
35
  # str.size
34
36
  # str.empty?
35
37
  #
36
- # # For example, if the receiver is a blank string, it will be incompatible.
38
+ # # For example, if the receiver is an empty string, it will be incompatible.
37
39
  # # If a negative value is specified for the receiver, `nil` is returned.
38
- # str.chars.last # Incompatible with `str[-1]`.
39
40
  # str.chars.last(2) # Incompatible with `str[-2..-1].chars`.
40
41
  # str.chars.drop(2) # Incompatible with `str[2..-1].chars`.
41
42
  #
@@ -44,7 +45,7 @@ module RuboCop
44
45
  extend AutoCorrector
45
46
 
46
47
  MSG = 'Use `%<good_method>s` instead of `%<bad_method>s`.'
47
- RESTRICT_ON_SEND = %i[[] slice first take length size empty?].freeze
48
+ RESTRICT_ON_SEND = %i[[] slice first last take length size empty?].freeze
48
49
 
49
50
  def_node_matcher :redundant_chars_call?, <<~PATTERN
50
51
  (send $(send _ :chars) $_ $...)
@@ -52,6 +53,7 @@ module RuboCop
52
53
 
53
54
  def on_send(node)
54
55
  return unless (receiver, method, args = redundant_chars_call?(node))
56
+ return if method == :last && !args.empty?
55
57
 
56
58
  range = offense_range(receiver, node)
57
59
  message = build_message(method, args)
@@ -67,11 +69,11 @@ module RuboCop
67
69
  private
68
70
 
69
71
  def offense_range(receiver, node)
70
- range_between(receiver.loc.selector.begin_pos, node.loc.expression.end_pos)
72
+ range_between(receiver.loc.selector.begin_pos, node.source_range.end_pos)
71
73
  end
72
74
 
73
75
  def correction_range(receiver, node)
74
- range_between(receiver.loc.dot.begin_pos, node.loc.expression.end_pos)
76
+ range_between(receiver.loc.dot.begin_pos, node.source_range.end_pos)
75
77
  end
76
78
 
77
79
  def build_message(method, args)
@@ -86,6 +88,8 @@ module RuboCop
86
88
  "[#{build_call_args(args)}].chars"
87
89
  when :[], :first
88
90
  build_good_method_for_brackets_or_first_method(method, args)
91
+ when :last
92
+ '[-1]'
89
93
  when :take
90
94
  "[0...#{args.first.source}].chars"
91
95
  else
@@ -74,6 +74,9 @@ module RuboCop
74
74
  # end
75
75
  class RegexpMatch < Base
76
76
  extend AutoCorrector
77
+ extend TargetRubyVersion
78
+
79
+ minimum_target_ruby_version 2.4
77
80
 
78
81
  # Constants are included in this list because it is unlikely that
79
82
  # someone will store `nil` as a constant and then use it for comparison
@@ -121,13 +124,17 @@ module RuboCop
121
124
 
122
125
  def_node_search :last_matches, <<~PATTERN
123
126
  {
124
- (send (const nil? :Regexp) :last_match)
125
- (send (const nil? :Regexp) :last_match _)
127
+ (send (const {nil? cbase} :Regexp) :last_match)
128
+ (send (const {nil? cbase} :Regexp) :last_match _)
126
129
  ({back_ref nth_ref} _)
127
130
  (gvar #match_gvar?)
128
131
  }
129
132
  PATTERN
130
133
 
134
+ def self.autocorrect_incompatible_with
135
+ [ConstantRegexp]
136
+ end
137
+
131
138
  def on_if(node)
132
139
  check_condition(node.condition)
133
140
  end
@@ -182,9 +189,9 @@ module RuboCop
182
189
 
183
190
  def range_to_search_for_last_matches(match_node, body, scope_root)
184
191
  expression = if modifier_form?(match_node)
185
- match_node.parent.if_branch.loc.expression
192
+ match_node.parent.if_branch.source_range
186
193
  else
187
- match_node.loc.expression
194
+ match_node.source_range
188
195
  end
189
196
 
190
197
  match_node_pos = expression.begin_pos
@@ -196,15 +203,15 @@ module RuboCop
196
203
  def next_match_pos(body, match_node_pos, scope_root)
197
204
  node = search_match_nodes(body).find do |match|
198
205
  begin_pos = if modifier_form?(match)
199
- match.parent.if_branch.loc.expression.begin_pos
206
+ match.parent.if_branch.source_range.begin_pos
200
207
  else
201
- match.loc.expression.begin_pos
208
+ match.source_range.begin_pos
202
209
  end
203
210
 
204
211
  begin_pos > match_node_pos && scope_root(match) == scope_root
205
212
  end
206
213
 
207
- node ? node.loc.expression.begin_pos : Float::INFINITY
214
+ node ? node.source_range.begin_pos : Float::INFINITY
208
215
  end
209
216
 
210
217
  def modifier_form?(match_node)
@@ -213,9 +220,8 @@ module RuboCop
213
220
 
214
221
  def find_last_match(body, range, scope_root)
215
222
  last_matches(body).find do |ref|
216
- ref_pos = ref.loc.expression.begin_pos
217
- range.cover?(ref_pos) &&
218
- scope_root(ref) == scope_root
223
+ ref_pos = ref.source_range.begin_pos
224
+ range.cover?(ref_pos) && scope_root(ref) == scope_root
219
225
  end
220
226
  end
221
227
 
@@ -238,14 +244,7 @@ module RuboCop
238
244
  end
239
245
 
240
246
  def match_gvar?(sym)
241
- %i[
242
- $~
243
- $MATCH
244
- $PREMATCH
245
- $POSTMATCH
246
- $LAST_PAREN_MATCH
247
- $LAST_MATCH_INFO
248
- ].include?(sym)
247
+ %i[$~ $MATCH $PREMATCH $POSTMATCH $LAST_PAREN_MATCH $LAST_MATCH_INFO].include?(sym)
249
248
  end
250
249
 
251
250
  def correct_operator(corrector, recv, arg, oper = nil)
@@ -253,8 +252,8 @@ module RuboCop
253
252
 
254
253
  replace_with_match_predicate_method(corrector, recv, arg, op_range)
255
254
 
256
- corrector.insert_after(arg.loc.expression, ')') unless op_range.source.end_with?('(')
257
- corrector.insert_before(recv.loc.expression, '!') if oper == :!~
255
+ corrector.insert_after(arg, ')') unless op_range.source.end_with?('(')
256
+ corrector.insert_before(recv, '!') if oper == :!~
258
257
  end
259
258
 
260
259
  def replace_with_match_predicate_method(corrector, recv, arg, op_range)
@@ -269,14 +268,14 @@ module RuboCop
269
268
  end
270
269
 
271
270
  def swap_receiver_and_arg(corrector, recv, arg)
272
- corrector.replace(recv.loc.expression, arg.source)
273
- corrector.replace(arg.loc.expression, recv.source)
271
+ corrector.replace(recv, arg.source)
272
+ corrector.replace(arg, recv.source)
274
273
  end
275
274
 
276
275
  def correction_range(recv, arg)
277
276
  buffer = processed_source.buffer
278
- op_begin_pos = recv.loc.expression.end_pos
279
- op_end_pos = arg.loc.expression.begin_pos
277
+ op_begin_pos = recv.source_range.end_pos
278
+ op_end_pos = arg.source_range.begin_pos
280
279
  Parser::Source::Range.new(buffer, op_begin_pos, op_end_pos)
281
280
  end
282
281
  end
@@ -3,8 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # This cop is used to identify usages of `reverse.each` and
7
- # change them to use `reverse_each` instead.
6
+ # Identifies usages of `reverse.each` and change them to use `reverse_each` instead.
8
7
  #
9
8
  # If the return value is used, it will not be detected because the result will be different.
10
9
  #
@@ -28,7 +27,7 @@ module RuboCop
28
27
  RESTRICT_ON_SEND = %i[each].freeze
29
28
 
30
29
  def_node_matcher :reverse_each?, <<~MATCHER
31
- (send (send _ :reverse) :each)
30
+ (send (call _ :reverse) :each)
32
31
  MATCHER
33
32
 
34
33
  def on_send(node)
@@ -42,6 +41,7 @@ module RuboCop
42
41
  end
43
42
  end
44
43
  end
44
+ alias on_csend on_send
45
45
 
46
46
  private
47
47
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # This cop identifies places where `reverse.first(n)` and `reverse.first`
6
+ # Identifies places where `reverse.first(n)` and `reverse.first`
7
7
  # can be replaced by `last(n).reverse` and `last`.
8
8
  #
9
9
  # @example
@@ -24,7 +24,7 @@ module RuboCop
24
24
  RESTRICT_ON_SEND = %i[first].freeze
25
25
 
26
26
  def_node_matcher :reverse_first_candidate?, <<~PATTERN
27
- (send $(send _ :reverse) :first (int _)?)
27
+ (send $(call _ :reverse) :first (int _)?)
28
28
  PATTERN
29
29
 
30
30
  def on_send(node)
@@ -39,11 +39,12 @@ module RuboCop
39
39
  end
40
40
  end
41
41
  end
42
+ alias on_csend on_send
42
43
 
43
44
  private
44
45
 
45
46
  def correction_range(receiver, node)
46
- range_between(receiver.loc.selector.begin_pos, node.loc.expression.end_pos)
47
+ range_between(receiver.loc.selector.begin_pos, node.source_range.end_pos)
47
48
  end
48
49
 
49
50
  def build_message(node)
@@ -38,6 +38,7 @@ module RuboCop
38
38
  range = offense_range(node, map_method)
39
39
  add_offense(range, message: format(MSG, method_name: node.method_name))
40
40
  end
41
+ alias on_csend on_send
41
42
 
42
43
  private
43
44
 
@@ -52,7 +53,7 @@ module RuboCop
52
53
  end
53
54
 
54
55
  def offense_range(node, map_method)
55
- range_between(node.loc.selector.begin_pos, map_method.loc.expression.end_pos)
56
+ range_between(node.loc.selector.begin_pos, map_method.source_range.end_pos)
56
57
  end
57
58
  end
58
59
  end
@@ -3,8 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # This cop is used to identify usages of `count` on an
7
- # `Array` and `Hash` and change them to `size`.
6
+ # Identifies usages of `count` on an `Array` and `Hash` and change them to `size`.
8
7
  #
9
8
  # @example
10
9
  # # bad
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # This cop identifies places where `sort { |a, b| b <=> a }`
6
+ # Identifies places where `sort { |a, b| b <=> a }`
7
7
  # can be replaced by a faster `sort.reverse`.
8
8
  #
9
9
  # @example
@@ -17,27 +17,36 @@ module RuboCop
17
17
  include SortBlock
18
18
  extend AutoCorrector
19
19
 
20
- MSG = 'Use `sort.reverse` instead of `%<bad_method>s`.'
20
+ MSG = 'Use `sort.reverse` instead.'
21
21
 
22
22
  def on_block(node)
23
23
  sort_with_block?(node) do |send, var_a, var_b, body|
24
24
  replaceable_body?(body, var_b, var_a) do
25
- range = sort_range(send, node)
25
+ register_offense(send, node)
26
+ end
27
+ end
28
+ end
26
29
 
27
- add_offense(range, message: message(var_a, var_b)) do |corrector|
28
- replacement = 'sort.reverse'
30
+ def on_numblock(node)
31
+ sort_with_numblock?(node) do |send, arg_count, body|
32
+ next unless arg_count == 2
29
33
 
30
- corrector.replace(range, replacement)
31
- end
34
+ replaceable_body?(body, :_2, :_1) do
35
+ register_offense(send, node)
32
36
  end
33
37
  end
34
38
  end
35
39
 
36
40
  private
37
41
 
38
- def message(var_a, var_b)
39
- bad_method = "sort { |#{var_a}, #{var_b}| #{var_b} <=> #{var_a} }"
40
- format(MSG, bad_method: bad_method)
42
+ def register_offense(send, node)
43
+ range = sort_range(send, node)
44
+
45
+ add_offense(range) do |corrector|
46
+ replacement = 'sort.reverse'
47
+
48
+ corrector.replace(range, replacement)
49
+ end
41
50
  end
42
51
  end
43
52
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # This cop identifies places where `gsub(/a+/, 'a')` and `gsub!(/a+/, 'a')`
6
+ # Identifies places where `gsub(/a+/, 'a')` and `gsub!(/a+/, 'a')`
7
7
  # can be replaced by `squeeze('a')` and `squeeze!('a')`.
8
8
  #
9
9
  # The `squeeze('a')` method is faster than `gsub(/a+/, 'a')`.
@@ -24,13 +24,10 @@ module RuboCop
24
24
  MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
25
25
  RESTRICT_ON_SEND = %i[gsub gsub!].freeze
26
26
 
27
- PREFERRED_METHODS = {
28
- gsub: :squeeze,
29
- gsub!: :squeeze!
30
- }.freeze
27
+ PREFERRED_METHODS = { gsub: :squeeze, gsub!: :squeeze! }.freeze
31
28
 
32
29
  def_node_matcher :squeeze_candidate?, <<~PATTERN
33
- (send
30
+ (call
34
31
  $!nil? ${:gsub :gsub!}
35
32
  (regexp
36
33
  (str $#repeating_literal?)
@@ -38,6 +35,7 @@ module RuboCop
38
35
  (str $_))
39
36
  PATTERN
40
37
 
38
+ # rubocop:disable Metrics/AbcSize
41
39
  def on_send(node)
42
40
  squeeze_candidate?(node) do |receiver, bad_method, regexp_str, replace_str|
43
41
  regexp_str = regexp_str[0..-2] # delete '+' from the end
@@ -49,12 +47,14 @@ module RuboCop
49
47
 
50
48
  add_offense(node.loc.selector, message: message) do |corrector|
51
49
  string_literal = to_string_literal(replace_str)
52
- new_code = "#{receiver.source}.#{good_method}(#{string_literal})"
50
+ new_code = "#{receiver.source}#{node.loc.dot.source}#{good_method}(#{string_literal})"
53
51
 
54
- corrector.replace(node.source_range, new_code)
52
+ corrector.replace(node, new_code)
55
53
  end
56
54
  end
57
55
  end
56
+ # rubocop:enable Metrics/AbcSize
57
+ alias on_csend on_send
58
58
 
59
59
  private
60
60
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # This cop identifies unnecessary use of a regex where `String#start_with?` would suffice.
6
+ # Identifies unnecessary use of a regex where `String#start_with?` would suffice.
7
7
  #
8
8
  # This cop has `SafeMultiline` configuration option that `true` by default because
9
9
  # `^start` is unsafe as it will behave incompatible with `start_with?`
@@ -50,12 +50,11 @@ module RuboCop
50
50
  include RegexpMetacharacter
51
51
  extend AutoCorrector
52
52
 
53
- MSG = 'Use `String#start_with?` instead of a regex match anchored to ' \
54
- 'the beginning of the string.'
53
+ MSG = 'Use `String#start_with?` instead of a regex match anchored to the beginning of the string.'
55
54
  RESTRICT_ON_SEND = %i[match =~ match?].freeze
56
55
 
57
56
  def_node_matcher :redundant_regex?, <<~PATTERN
58
- {(send $!nil? {:match :=~ :match?} (regexp (str $#literal_at_start?) (regopt)))
57
+ {(call $!nil? {:match :=~ :match?} (regexp (str $#literal_at_start?) (regopt)))
59
58
  (send (regexp (str $#literal_at_start?) (regopt)) {:match :match?} $_)
60
59
  (match-with-lvasgn (regexp (str $#literal_at_start?) (regopt)) $_)}
61
60
  PATTERN
@@ -67,12 +66,14 @@ module RuboCop
67
66
  receiver, regex_str = regex_str, receiver if receiver.is_a?(String)
68
67
  regex_str = drop_start_metacharacter(regex_str)
69
68
  regex_str = interpret_string_escapes(regex_str)
69
+ dot = node.loc.dot ? node.loc.dot.source : '.'
70
70
 
71
- new_source = "#{receiver.source}.start_with?(#{to_string_literal(regex_str)})"
71
+ new_source = "#{receiver.source}#{dot}start_with?(#{to_string_literal(regex_str)})"
72
72
 
73
- corrector.replace(node.source_range, new_source)
73
+ corrector.replace(node, new_source)
74
74
  end
75
75
  end
76
+ alias on_csend on_send
76
77
  alias on_match_with_lvasgn on_send
77
78
  end
78
79
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Performance
6
- # This cop identifies places where string identifier argument can be replaced
6
+ # Identifies places where string identifier argument can be replaced
7
7
  # by symbol identifier argument.
8
8
  # It prevents the redundancy of the internal string-to-symbol conversion.
9
9
  #
@@ -27,28 +27,33 @@ module RuboCop
27
27
 
28
28
  MSG = 'Use `%<symbol_arg>s` instead of `%<string_arg>s`.'
29
29
 
30
+ COMMAND_METHODS = %i[
31
+ alias_method attr_accessor attr_reader attr_writer autoload autoload? private private_constant
32
+ protected public public_constant module_function
33
+ ].freeze
34
+
30
35
  # NOTE: `attr` method is not included in this list as it can cause false positives in Nokogiri API.
31
36
  # And `attr` may not be used because `Style/Attr` registers an offense.
32
37
  # https://github.com/rubocop/rubocop-performance/issues/278
33
- RESTRICT_ON_SEND = %i[
34
- alias_method attr_accessor attr_reader attr_writer autoload autoload?
38
+ RESTRICT_ON_SEND = (%i[
35
39
  class_variable_defined? const_defined? const_get const_set const_source_location
36
40
  define_method instance_method method_defined? private_class_method? private_method_defined?
37
41
  protected_method_defined? public_class_method public_instance_method public_method_defined?
38
42
  remove_class_variable remove_method undef_method class_variable_get class_variable_set
39
- deprecate_constant module_function private private_constant protected public public_constant
40
- remove_const ruby2_keywords
41
- define_singleton_method instance_variable_defined instance_variable_get instance_variable_set
42
- method public_method public_send remove_instance_variable respond_to? send singleton_method
43
- __send__
44
- ].freeze
43
+ deprecate_constant remove_const ruby2_keywords define_singleton_method instance_variable_defined?
44
+ instance_variable_get instance_variable_set method public_method public_send remove_instance_variable
45
+ respond_to? send singleton_method __send__
46
+ ] + COMMAND_METHODS).freeze
45
47
 
46
48
  def on_send(node)
49
+ return if COMMAND_METHODS.include?(node.method_name) && node.receiver
47
50
  return unless (first_argument = node.first_argument)
48
51
  return unless first_argument.str_type?
49
- return if first_argument.value.include?(' ')
50
52
 
51
- replacement = first_argument.value.to_sym.inspect
53
+ first_argument_value = first_argument.value
54
+ return if first_argument_value.include?(' ') || first_argument_value.include?('::')
55
+
56
+ replacement = first_argument_value.to_sym.inspect
52
57
 
53
58
  message = format(MSG, symbol_arg: replacement, string_arg: first_argument.source)
54
59