rubocop-performance 1.19.0 → 1.20.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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -0
  3. data/config/default.yml +16 -16
  4. data/lib/rubocop/cop/mixin/sort_block.rb +2 -2
  5. data/lib/rubocop/cop/performance/array_semi_infinite_range_slice.rb +1 -1
  6. data/lib/rubocop/cop/performance/block_given_with_explicit_block.rb +4 -0
  7. data/lib/rubocop/cop/performance/count.rb +5 -5
  8. data/lib/rubocop/cop/performance/fixed_size.rb +2 -1
  9. data/lib/rubocop/cop/performance/flat_map.rb +4 -3
  10. data/lib/rubocop/cop/performance/inefficient_hash_search.rb +2 -2
  11. data/lib/rubocop/cop/performance/map_compact.rb +2 -2
  12. data/lib/rubocop/cop/performance/map_method_chain.rb +3 -1
  13. data/lib/rubocop/cop/performance/range_include.rb +8 -6
  14. data/lib/rubocop/cop/performance/redundant_equality_comparison_block.rb +1 -1
  15. data/lib/rubocop/cop/performance/redundant_match.rb +30 -1
  16. data/lib/rubocop/cop/performance/redundant_merge.rb +3 -1
  17. data/lib/rubocop/cop/performance/reverse_each.rb +1 -1
  18. data/lib/rubocop/cop/performance/reverse_first.rb +5 -13
  19. data/lib/rubocop/cop/performance/select_map.rb +2 -6
  20. data/lib/rubocop/cop/performance/size.rb +4 -3
  21. data/lib/rubocop/cop/performance/sort_reverse.rb +5 -4
  22. data/lib/rubocop/cop/performance/string_identifier_argument.rb +16 -2
  23. data/lib/rubocop/cop/performance/string_include.rb +3 -2
  24. data/lib/rubocop/cop/performance/sum.rb +11 -9
  25. data/lib/rubocop/cop/performance/times_map.rb +14 -2
  26. data/lib/rubocop/cop/performance/unfreeze_string.rb +6 -3
  27. data/lib/rubocop/performance/version.rb +1 -1
  28. data/lib/rubocop-performance.rb +8 -0
  29. metadata +14 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 06f3e8346dc7f9be72a1f18c62a25dc02aeac41debcfe3c58df68e2a6904df43
4
- data.tar.gz: f01facdb92a3056d05990e2ed2b6b1920de0501edf53a08e95e08620651c8557
3
+ metadata.gz: afce4fa4bdd79fa5f4429edcdb3fa157f94be3f2526630db7d342c56fd5d741b
4
+ data.tar.gz: 833a0a5c44c55a7e30640c7658f54e5a28c5a362add04c60b434fa9f58b61136
5
5
  SHA512:
6
- metadata.gz: 07eb541698b6ccf2985ef62392bd78703bf6607e2877ef3865ab1762d62910c4c346fbb7e9bc48af7b7d98b0e1ad22e8c79ea2425555fbe75c2a5e614837eaa7
7
- data.tar.gz: 60fc9f900906cca518d0da62170f71ae6e5f5ffd44f4c1cbe75af83f9a1fef252b6bab95d3af4f49f328d4a856cd17c7f47621ee62575ab282eacfd26dc09841
6
+ metadata.gz: 62dea0dda6f9fc634e7d7d418ba980bb106d698db3d7242da2c81c9abc49124748dc553bf413e9281fe6969d1b29ef991d58e2e2a6211c759f27cbe36a99cfe4
7
+ data.tar.gz: 046a795365aa47793e3afa36cc0685cc44851573210669945a8b6bda73d8edcb38ca6acc522d17009ea722a6c84e68c21ddc759181ba1840cac7c566e76b0220
data/README.md CHANGED
@@ -53,6 +53,8 @@ $ rubocop --require rubocop-performance
53
53
  ### Rake task
54
54
 
55
55
  ```ruby
56
+ require 'rubocop/rake_task'
57
+
56
58
  RuboCop::RakeTask.new do |task|
57
59
  task.requires << 'rubocop-performance'
58
60
  end
data/config/default.yml CHANGED
@@ -6,7 +6,7 @@ Performance:
6
6
 
7
7
  Performance/AncestorsInclude:
8
8
  Description: 'Use `A <= B` instead of `A.ancestors.include?(B)`.'
9
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#ancestorsinclude-vs--code'
9
+ Reference: 'https://github.com/fastruby/fast-ruby#ancestorsinclude-vs--code'
10
10
  Enabled: 'pending'
11
11
  Safe: false
12
12
  VersionAdded: '1.7'
@@ -54,7 +54,7 @@ Performance/CaseWhenSplat:
54
54
  Performance/Casecmp:
55
55
  Description: >-
56
56
  Use `casecmp` rather than `downcase ==`, `upcase ==`, `== downcase`, or `== upcase`..
57
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringcasecmp-vs-stringdowncase---code'
57
+ Reference: 'https://github.com/fastruby/fast-ruby#stringcasecmp-vs--stringcasecmp-vs-stringdowncase---code'
58
58
  Enabled: true
59
59
  Safe: false
60
60
  VersionAdded: '0.36'
@@ -122,7 +122,7 @@ Performance/Detect:
122
122
  Description: >-
123
123
  Use `detect` instead of `select.first`, `find_all.first`, `filter.first`,
124
124
  `select.last`, `find_all.last`, and `filter.last`.
125
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code'
125
+ Reference: 'https://github.com/fastruby/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code'
126
126
  # This cop has known compatibility issues with `ActiveRecord` and other
127
127
  # frameworks. `ActiveRecord` does not implement a `detect` method and `find`
128
128
  # has its own meaning. Correcting `ActiveRecord` methods with this cop
@@ -145,7 +145,7 @@ Performance/DoubleStartEndWith:
145
145
 
146
146
  Performance/EndWith:
147
147
  Description: 'Use `end_with?` instead of a regex match anchored to the end of a string.'
148
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringmatch-vs-stringstart_withstringend_with-code-start-code-end'
148
+ Reference: 'https://github.com/fastruby/fast-ruby#stringmatch-vs-stringmatch-vs-stringstart_withstringend_with-code-start-code-end'
149
149
  # This will change to a new method call which isn't guaranteed to be on the
150
150
  # object. Switching these methods has to be done with knowledge of the types
151
151
  # of the variables which rubocop doesn't have.
@@ -165,7 +165,7 @@ Performance/FlatMap:
165
165
  Use `Enumerable#flat_map`
166
166
  instead of `Enumerable#map...Array#flatten(1)`
167
167
  or `Enumerable#collect..Array#flatten(1)`.
168
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code'
168
+ Reference: 'https://github.com/fastruby/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code'
169
169
  Enabled: true
170
170
  VersionAdded: '0.30'
171
171
  EnabledForFlattenWithoutParams: false
@@ -176,7 +176,7 @@ Performance/FlatMap:
176
176
 
177
177
  Performance/InefficientHashSearch:
178
178
  Description: 'Use `key?` or `value?` instead of `keys.include?` or `values.include?`.'
179
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#hashkey-instead-of-hashkeysinclude-code'
179
+ Reference: 'https://github.com/fastruby/fast-ruby#hashkey-instead-of-hashkeysinclude-code'
180
180
  Enabled: true
181
181
  VersionAdded: '0.56'
182
182
  Safe: false
@@ -201,7 +201,7 @@ Performance/MapMethodChain:
201
201
 
202
202
  Performance/MethodObjectAsBlock:
203
203
  Description: 'Use block explicitly instead of block-passing a method object.'
204
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#normal-way-to-apply-method-vs-method-code'
204
+ Reference: 'https://github.com/fastruby/fast-ruby#normal-way-to-apply-method-vs-method-code'
205
205
  Enabled: pending
206
206
  VersionAdded: '1.9'
207
207
 
@@ -213,7 +213,7 @@ Performance/OpenStruct:
213
213
 
214
214
  Performance/RangeInclude:
215
215
  Description: 'Use `Range#cover?` instead of `Range#include?` (or `Range#member?`).'
216
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#cover-vs-include-code'
216
+ Reference: 'https://github.com/fastruby/fast-ruby#cover-vs-include-code'
217
217
  Enabled: true
218
218
  VersionAdded: '0.36'
219
219
  VersionChanged: '1.7'
@@ -221,7 +221,7 @@ Performance/RangeInclude:
221
221
 
222
222
  Performance/RedundantBlockCall:
223
223
  Description: 'Use `yield` instead of `block.call`.'
224
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#proccall-and-block-arguments-vs-yieldcode'
224
+ Reference: 'https://github.com/fastruby/fast-ruby#proccall-and-block-arguments-vs-yieldcode'
225
225
  Enabled: true
226
226
  VersionAdded: '0.36'
227
227
 
@@ -244,7 +244,7 @@ Performance/RedundantMatch:
244
244
 
245
245
  Performance/RedundantMerge:
246
246
  Description: 'Use Hash#[]=, rather than Hash#merge! with a single key-value pair.'
247
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#hashmerge-vs-hash-code'
247
+ Reference: 'https://github.com/fastruby/fast-ruby#hashmerge-vs-hash-code'
248
248
  Enabled: true
249
249
  Safe: false
250
250
  VersionAdded: '0.36'
@@ -271,13 +271,13 @@ Performance/RegexpMatch:
271
271
  Description: >-
272
272
  Use `match?` instead of `Regexp#match`, `String#match`, `Symbol#match`,
273
273
  `Regexp#===`, or `=~` when `MatchData` is not used.
274
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#regexp-vs-stringmatch-vs-string-vs-stringmatch-code-'
274
+ Reference: 'https://github.com/fastruby/fast-ruby#regexp-vs-regexpmatch-vs-regexpmatch-vs-stringmatch-vs-string-vs-stringmatch-code-'
275
275
  Enabled: true
276
276
  VersionAdded: '0.47'
277
277
 
278
278
  Performance/ReverseEach:
279
279
  Description: 'Use `reverse_each` instead of `reverse.each`.'
280
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablereverseeach-vs-enumerablereverse_each-code'
280
+ Reference: 'https://github.com/fastruby/fast-ruby#enumerablereverseeach-vs-enumerablereverse_each-code'
281
281
  Enabled: true
282
282
  VersionAdded: '0.30'
283
283
 
@@ -295,7 +295,7 @@ Performance/Size:
295
295
  Description: >-
296
296
  Use `size` instead of `count` for counting
297
297
  the number of elements in `Array` and `Hash`.
298
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#arraylength-vs-arraysize-vs-arraycount-code'
298
+ Reference: 'https://github.com/fastruby/fast-ruby#arraylength-vs-arraysize-vs-arraycount-code'
299
299
  Enabled: true
300
300
  VersionAdded: '0.30'
301
301
 
@@ -306,13 +306,13 @@ Performance/SortReverse:
306
306
 
307
307
  Performance/Squeeze:
308
308
  Description: "Use `squeeze('a')` instead of `gsub(/a+/, 'a')`."
309
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#remove-extra-spaces-or-other-contiguous-characters-code'
309
+ Reference: 'https://github.com/fastruby/fast-ruby#remove-extra-spaces-or-other-contiguous-characters-code'
310
310
  Enabled: 'pending'
311
311
  VersionAdded: '1.7'
312
312
 
313
313
  Performance/StartWith:
314
314
  Description: 'Use `start_with?` instead of a regex match anchored to the beginning of a string.'
315
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringmatch-vs-stringstart_withstringend_with-code-start-code-end'
315
+ Reference: 'https://github.com/fastruby/fast-ruby#stringmatch-vs-stringmatch-vs-stringstart_withstringend_with-code-start-code-end'
316
316
  # This will change to a new method call which isn't guaranteed to be on the
317
317
  # object. Switching these methods has to be done with knowledge of the types
318
318
  # of the variables which rubocop doesn't have.
@@ -339,7 +339,7 @@ Performance/StringReplacement:
339
339
  Use `tr` instead of `gsub` when you are replacing the same
340
340
  number of characters. Use `delete` instead of `gsub` when
341
341
  you are deleting characters.
342
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringgsub-vs-stringtr-code'
342
+ Reference: 'https://github.com/fastruby/fast-ruby#stringgsub-vs-stringtr-code'
343
343
  Enabled: true
344
344
  VersionAdded: '0.33'
345
345
 
@@ -9,14 +9,14 @@ module RuboCop
9
9
 
10
10
  def_node_matcher :sort_with_block?, <<~PATTERN
11
11
  (block
12
- $(send _ :sort)
12
+ $(call _ :sort)
13
13
  (args (arg $_a) (arg $_b))
14
14
  $send)
15
15
  PATTERN
16
16
 
17
17
  def_node_matcher :sort_with_numblock?, <<~PATTERN
18
18
  (numblock
19
- $(send _ :sort)
19
+ $(call _ :sort)
20
20
  $_arg_count
21
21
  $send)
22
22
  PATTERN
@@ -39,7 +39,7 @@ module RuboCop
39
39
  RESTRICT_ON_SEND = SLICE_METHODS
40
40
 
41
41
  def_node_matcher :endless_range_slice?, <<~PATTERN
42
- (call $_ $%SLICE_METHODS $#endless_range?)
42
+ (call $!{str dstr xstr} $%SLICE_METHODS $#endless_range?)
43
43
  PATTERN
44
44
 
45
45
  def_node_matcher :endless_range?, <<~PATTERN
@@ -47,6 +47,10 @@ module RuboCop
47
47
  corrector.replace(node, block_arg_name)
48
48
  end
49
49
  end
50
+
51
+ def self.autocorrect_incompatible_with
52
+ [Lint::UnusedMethodArgument]
53
+ end
50
54
  end
51
55
  end
52
56
  end
@@ -9,8 +9,7 @@ module RuboCop
9
9
  #
10
10
  # @safety
11
11
  # This cop is unsafe because it has known compatibility issues with `ActiveRecord` and other
12
- # frameworks. ActiveRecord's `count` ignores the block that is passed to it.
13
- # `ActiveRecord` will ignore the block that is passed to `count`.
12
+ # frameworks. Before Rails 5.1, `ActiveRecord` will ignore the block that is passed to `count`.
14
13
  # Other methods, such as `select`, will convert the association to an
15
14
  # array and then run the block on the array. A simple work around to
16
15
  # make `count` work with a block is to call `to_a.count {...}`.
@@ -55,8 +54,8 @@ module RuboCop
55
54
 
56
55
  def_node_matcher :count_candidate?, <<~PATTERN
57
56
  {
58
- (send (block $(send _ ${:select :filter :find_all :reject}) ...) ${:count :length :size})
59
- (send $(send _ ${:select :filter :find_all :reject} (:block_pass _)) ${:count :length :size})
57
+ (call (block $(call _ ${:select :filter :find_all :reject}) ...) ${:count :length :size})
58
+ (call $(call _ ${:select :filter :find_all :reject} (:block_pass _)) ${:count :length :size})
60
59
  }
61
60
  PATTERN
62
61
 
@@ -73,6 +72,7 @@ module RuboCop
73
72
  end
74
73
  end
75
74
  end
75
+ alias on_csend on_send
76
76
 
77
77
  private
78
78
 
@@ -101,7 +101,7 @@ module RuboCop
101
101
  end
102
102
 
103
103
  def negate_reject(corrector, node)
104
- if node.receiver.send_type?
104
+ if node.receiver.call_type?
105
105
  negate_block_pass_reject(corrector, node)
106
106
  else
107
107
  negate_block_reject(corrector, node)
@@ -50,7 +50,7 @@ module RuboCop
50
50
  RESTRICT_ON_SEND = %i[count length size].freeze
51
51
 
52
52
  def_node_matcher :counter, <<~MATCHER
53
- (send ${array hash str sym} {:count :length :size} $...)
53
+ (call ${array hash str sym} {:count :length :size} $...)
54
54
  MATCHER
55
55
 
56
56
  def on_send(node)
@@ -62,6 +62,7 @@ module RuboCop
62
62
  add_offense(node)
63
63
  end
64
64
  end
65
+ alias on_csend on_send
65
66
 
66
67
  private
67
68
 
@@ -26,10 +26,10 @@ module RuboCop
26
26
  'multiple levels.'
27
27
 
28
28
  def_node_matcher :flat_map_candidate?, <<~PATTERN
29
- (send
29
+ (call
30
30
  {
31
- $(block (send _ ${:collect :map}) ...)
32
- $(send _ ${:collect :map} (block_pass _))
31
+ $(block (call _ ${:collect :map}) ...)
32
+ $(call _ ${:collect :map} (block_pass _))
33
33
  }
34
34
  ${:flatten :flatten!}
35
35
  $...
@@ -46,6 +46,7 @@ module RuboCop
46
46
  end
47
47
  end
48
48
  end
49
+ alias on_csend on_send
49
50
 
50
51
  private
51
52
 
@@ -45,7 +45,7 @@ module RuboCop
45
45
  RESTRICT_ON_SEND = %i[include?].freeze
46
46
 
47
47
  def_node_matcher :inefficient_include?, <<~PATTERN
48
- (send (call $_ {:keys :values}) :include? _)
48
+ (call (call $_ {:keys :values}) :include? _)
49
49
  PATTERN
50
50
 
51
51
  def on_send(node)
@@ -89,7 +89,7 @@ module RuboCop
89
89
  end
90
90
 
91
91
  def correct_argument(node)
92
- node.arguments.first.source
92
+ node.first_argument.source
93
93
  end
94
94
 
95
95
  def correct_hash_expression(node)
@@ -39,11 +39,11 @@ module RuboCop
39
39
 
40
40
  def_node_matcher :map_compact, <<~PATTERN
41
41
  {
42
- (send
42
+ (call
43
43
  $(call _ {:map :collect}
44
44
  (block_pass
45
45
  (sym _))) _)
46
- (send
46
+ (call
47
47
  (block
48
48
  $(call _ {:map :collect})
49
49
  (args ...) _) _)
@@ -68,6 +68,7 @@ module RuboCop
68
68
 
69
69
  private
70
70
 
71
+ # rubocop:disable Metrics/CyclomaticComplexity
71
72
  def find_begin_of_chained_map_method(node, map_args)
72
73
  return unless (chained_map_method = node.receiver)
73
74
  return if !chained_map_method.call_type? || !RESTRICT_ON_SEND.include?(chained_map_method.method_name)
@@ -77,10 +78,11 @@ module RuboCop
77
78
 
78
79
  receiver = chained_map_method.receiver
79
80
 
80
- return chained_map_method unless receiver.call_type? && block_pass_with_symbol_arg?(receiver.first_argument)
81
+ return chained_map_method unless receiver&.call_type? && block_pass_with_symbol_arg?(receiver.first_argument)
81
82
 
82
83
  find_begin_of_chained_map_method(chained_map_method, map_args)
83
84
  end
85
+ # rubocop:enable Metrics/CyclomaticComplexity
84
86
  end
85
87
  end
86
88
  end
@@ -12,6 +12,12 @@ module RuboCop
12
12
  # @safety
13
13
  # This cop is unsafe because `Range#include?` (or `Range#member?`) and `Range#cover?`
14
14
  # are not equivalent behavior.
15
+ # Example of a case where `Range#cover?` may not provide the desired result:
16
+ #
17
+ # [source,ruby]
18
+ # ----
19
+ # ('a'..'z').cover?('yellow') # => true
20
+ # ----
15
21
  #
16
22
  # @example
17
23
  # # bad
@@ -20,11 +26,6 @@ module RuboCop
20
26
  #
21
27
  # # good
22
28
  # ('a'..'z').cover?('b') # => true
23
- #
24
- # # Example of a case where `Range#cover?` may not provide
25
- # # the desired result:
26
- #
27
- # ('a'..'z').cover?('yellow') # => true
28
29
  class RangeInclude < Base
29
30
  extend AutoCorrector
30
31
 
@@ -37,7 +38,7 @@ module RuboCop
37
38
  # (We don't even catch it if the Range is in double parens)
38
39
 
39
40
  def_node_matcher :range_include, <<~PATTERN
40
- (send {irange erange (begin {irange erange})} ${:include? :member?} ...)
41
+ (call {irange erange (begin {irange erange})} ${:include? :member?} ...)
41
42
  PATTERN
42
43
 
43
44
  def on_send(node)
@@ -49,6 +50,7 @@ module RuboCop
49
50
  end
50
51
  end
51
52
  end
53
+ alias on_csend on_send
52
54
  end
53
55
  end
54
56
  end
@@ -63,7 +63,7 @@ module RuboCop
63
63
  return unless TARGET_METHODS.include?(node.method_name)
64
64
  return unless one_block_argument?(node.arguments)
65
65
 
66
- block_argument = node.arguments.first
66
+ block_argument = node.first_argument
67
67
  block_body = node.body
68
68
  return unless use_equality_comparison_block?(block_body)
69
69
  return if same_block_argument_and_is_a_argument?(block_body, block_argument)
@@ -23,6 +23,8 @@ module RuboCop
23
23
  MSG = 'Use `=~` in places where the `MatchData` returned by `#match` will not be used.'
24
24
  RESTRICT_ON_SEND = %i[match].freeze
25
25
 
26
+ HIGHER_PRECEDENCE_OPERATOR_METHODS = %i[| ^ & + - * / % ** > >= < <= << >>].freeze
27
+
26
28
  # 'match' is a fairly generic name, so we don't flag it unless we see
27
29
  # a string or regexp literal on one side or the other
28
30
  def_node_matcher :match_call?, <<~PATTERN
@@ -47,7 +49,7 @@ module RuboCop
47
49
  private
48
50
 
49
51
  def autocorrect(corrector, node)
50
- new_source = "#{node.receiver.source} =~ #{node.first_argument.source}"
52
+ new_source = "#{node.receiver.source} =~ #{replacement(node)}"
51
53
 
52
54
  corrector.replace(node, new_source)
53
55
  end
@@ -57,6 +59,33 @@ module RuboCop
57
59
  # register an offense in that case
58
60
  node.receiver.regexp_type? || node.first_argument.regexp_type?
59
61
  end
62
+
63
+ def replacement(node)
64
+ arg = node.first_argument
65
+
66
+ if requires_parentheses?(arg)
67
+ "(#{arg.source})"
68
+ else
69
+ arg.source
70
+ end
71
+ end
72
+
73
+ def requires_parentheses?(arg)
74
+ return true if arg.if_type? && arg.ternary?
75
+ return true if arg.and_type? || arg.or_type? || arg.range_type?
76
+
77
+ call_like?(arg) && requires_parentheses_for_call_like?(arg)
78
+ end
79
+
80
+ def requires_parentheses_for_call_like?(arg)
81
+ return false if arg.parenthesized? || !arg.arguments?
82
+
83
+ !HIGHER_PRECEDENCE_OPERATOR_METHODS.include?(arg.method_name)
84
+ end
85
+
86
+ def call_like?(arg)
87
+ arg.call_type? || arg.yield_type? || arg.super_type?
88
+ end
60
89
  end
61
90
  end
62
91
  end
@@ -130,7 +130,9 @@ module RuboCop
130
130
  end
131
131
 
132
132
  def rewrite_with_modifier(node, parent, new_source)
133
- indent = ' ' * configured_indentation_width
133
+ # FIXME: `|| 2` can be removed when support is limited to RuboCop 1.44 or higher.
134
+ # https://github.com/rubocop/rubocop/commit/02d1e5b
135
+ indent = ' ' * (configured_indentation_width || 2)
134
136
  padding = "\n#{indent + leading_spaces(node)}"
135
137
  new_source.gsub!("\n", padding)
136
138
 
@@ -27,7 +27,7 @@ module RuboCop
27
27
  RESTRICT_ON_SEND = %i[each].freeze
28
28
 
29
29
  def_node_matcher :reverse_each?, <<~MATCHER
30
- (send (call _ :reverse) :each)
30
+ (call (call _ :reverse) :each)
31
31
  MATCHER
32
32
 
33
33
  def on_send(node)
@@ -24,13 +24,13 @@ module RuboCop
24
24
  RESTRICT_ON_SEND = %i[first].freeze
25
25
 
26
26
  def_node_matcher :reverse_first_candidate?, <<~PATTERN
27
- (send $(call _ :reverse) :first (int _)?)
27
+ (call $(call _ :reverse) :first (int _)?)
28
28
  PATTERN
29
29
 
30
30
  def on_send(node)
31
31
  reverse_first_candidate?(node) do |receiver|
32
32
  range = correction_range(receiver, node)
33
- message = build_message(node)
33
+ message = build_message(node, range)
34
34
 
35
35
  add_offense(range, message: message) do |corrector|
36
36
  replacement = build_good_method(node)
@@ -47,27 +47,19 @@ module RuboCop
47
47
  range_between(receiver.loc.selector.begin_pos, node.source_range.end_pos)
48
48
  end
49
49
 
50
- def build_message(node)
50
+ def build_message(node, range)
51
51
  good_method = build_good_method(node)
52
- bad_method = build_bad_method(node)
52
+ bad_method = range.source
53
53
  format(MSG, good_method: good_method, bad_method: bad_method)
54
54
  end
55
55
 
56
56
  def build_good_method(node)
57
57
  if node.arguments?
58
- "last(#{node.arguments.first.source}).reverse"
58
+ "last(#{node.first_argument.source})#{node.loc.dot.source}reverse"
59
59
  else
60
60
  'last'
61
61
  end
62
62
  end
63
-
64
- def build_bad_method(node)
65
- if node.arguments?
66
- "reverse.first(#{node.arguments.first.source})"
67
- else
68
- 'reverse.first'
69
- end
70
- end
71
63
  end
72
64
  end
73
65
  end
@@ -24,10 +24,6 @@ module RuboCop
24
24
  MSG = 'Use `filter_map` instead of `%<method_name>s.map`.'
25
25
  RESTRICT_ON_SEND = %i[select filter].freeze
26
26
 
27
- def_node_matcher :bad_method?, <<~PATTERN
28
- (send nil? :bad_method ...)
29
- PATTERN
30
-
31
27
  def on_send(node)
32
28
  return if (first_argument = node.first_argument) && !first_argument.block_pass_type?
33
29
  return unless (send_node = map_method_candidate(node))
@@ -45,9 +41,9 @@ module RuboCop
45
41
  def map_method_candidate(node)
46
42
  return unless (parent = node.parent)
47
43
 
48
- if parent.block_type? && parent.parent&.send_type?
44
+ if parent.block_type? && parent.parent&.call_type?
49
45
  parent.parent
50
- elsif parent.send_type?
46
+ elsif parent.call_type?
51
47
  parent
52
48
  end
53
49
  end
@@ -43,7 +43,7 @@ module RuboCop
43
43
  def_node_matcher :array?, <<~PATTERN
44
44
  {
45
45
  [!nil? array_type?]
46
- (send _ :to_a)
46
+ (call _ :to_a)
47
47
  (send (const nil? :Array) :[] _)
48
48
  (send nil? :Array _)
49
49
  }
@@ -52,14 +52,14 @@ module RuboCop
52
52
  def_node_matcher :hash?, <<~PATTERN
53
53
  {
54
54
  [!nil? hash_type?]
55
- (send _ :to_h)
55
+ (call _ :to_h)
56
56
  (send (const nil? :Hash) :[] _)
57
57
  (send nil? :Hash _)
58
58
  }
59
59
  PATTERN
60
60
 
61
61
  def_node_matcher :count?, <<~PATTERN
62
- (send {#array? #hash?} :count)
62
+ (call {#array? #hash?} :count)
63
63
  PATTERN
64
64
 
65
65
  def on_send(node)
@@ -69,6 +69,7 @@ module RuboCop
69
69
  corrector.replace(node.loc.selector, 'size')
70
70
  end
71
71
  end
72
+ alias on_csend on_send
72
73
  end
73
74
  end
74
75
  end
@@ -17,7 +17,7 @@ module RuboCop
17
17
  include SortBlock
18
18
  extend AutoCorrector
19
19
 
20
- MSG = 'Use `sort.reverse` instead.'
20
+ MSG = 'Use `%<prefer>s` instead.'
21
21
 
22
22
  def on_block(node)
23
23
  sort_with_block?(node) do |send, var_a, var_b, body|
@@ -41,11 +41,12 @@ module RuboCop
41
41
 
42
42
  def register_offense(send, node)
43
43
  range = sort_range(send, node)
44
+ prefer = "sort#{send.loc.dot.source}reverse"
44
45
 
45
- add_offense(range) do |corrector|
46
- replacement = 'sort.reverse'
46
+ message = format(MSG, prefer: prefer)
47
47
 
48
- corrector.replace(range, replacement)
48
+ add_offense(range, message: message) do |corrector|
49
+ corrector.replace(range, prefer)
49
50
  end
50
51
  end
51
52
  end
@@ -16,11 +16,13 @@ module RuboCop
16
16
  # send('do_something')
17
17
  # attr_accessor 'do_something'
18
18
  # instance_variable_get('@ivar')
19
+ # const_get("string_#{interpolation}")
19
20
  #
20
21
  # # good
21
22
  # send(:do_something)
22
23
  # attr_accessor :do_something
23
24
  # instance_variable_get(:@ivar)
25
+ # const_get(:"string_#{interpolation}")
24
26
  #
25
27
  class StringIdentifierArgument < Base
26
28
  extend AutoCorrector
@@ -45,15 +47,16 @@ module RuboCop
45
47
  respond_to? send singleton_method __send__
46
48
  ] + COMMAND_METHODS).freeze
47
49
 
50
+ # rubocop:disable Metrics/CyclomaticComplexity
48
51
  def on_send(node)
49
52
  return if COMMAND_METHODS.include?(node.method_name) && node.receiver
50
53
  return unless (first_argument = node.first_argument)
51
- return unless first_argument.str_type?
54
+ return unless first_argument.str_type? || first_argument.dstr_type?
52
55
 
53
56
  first_argument_value = first_argument.value
54
57
  return if first_argument_value.include?(' ') || first_argument_value.include?('::')
55
58
 
56
- replacement = first_argument_value.to_sym.inspect
59
+ replacement = argument_replacement(first_argument, first_argument_value)
57
60
 
58
61
  message = format(MSG, symbol_arg: replacement, string_arg: first_argument.source)
59
62
 
@@ -61,6 +64,17 @@ module RuboCop
61
64
  corrector.replace(first_argument, replacement)
62
65
  end
63
66
  end
67
+ # rubocop:enable Metrics/CyclomaticComplexity
68
+
69
+ private
70
+
71
+ def argument_replacement(node, value)
72
+ if node.str_type?
73
+ value.to_sym.inspect
74
+ else
75
+ ":\"#{value.to_sym}\""
76
+ end
77
+ end
64
78
  end
65
79
  end
66
80
  end
@@ -16,6 +16,7 @@ module RuboCop
16
16
  # /ab/ =~ str
17
17
  # str.match(/ab/)
18
18
  # /ab/.match(str)
19
+ # /ab/ === str
19
20
  #
20
21
  # # good
21
22
  # str.include?('ab')
@@ -23,11 +24,11 @@ module RuboCop
23
24
  extend AutoCorrector
24
25
 
25
26
  MSG = 'Use `%<negation>sString#include?` instead of a regex match with literal-only pattern.'
26
- RESTRICT_ON_SEND = %i[match =~ !~ match?].freeze
27
+ RESTRICT_ON_SEND = %i[match =~ !~ match? ===].freeze
27
28
 
28
29
  def_node_matcher :redundant_regex?, <<~PATTERN
29
30
  {(call $!nil? {:match :=~ :!~ :match?} (regexp (str $#literal?) (regopt)))
30
- (send (regexp (str $#literal?) (regopt)) {:match :match?} $_)
31
+ (send (regexp (str $#literal?) (regopt)) {:match :match? :===} $_)
31
32
  (match-with-lvasgn (regexp (str $#literal?) (regopt)) $_)}
32
33
  PATTERN
33
34
 
@@ -80,21 +80,21 @@ module RuboCop
80
80
  RESTRICT_ON_SEND = %i[inject reduce sum].freeze
81
81
 
82
82
  def_node_matcher :sum_candidate?, <<~PATTERN
83
- (send _ ${:inject :reduce} $_init ? ${(sym :+) (block_pass (sym :+))})
83
+ (call _ ${:inject :reduce} $_init ? ${(sym :+) (block_pass (sym :+))})
84
84
  PATTERN
85
85
 
86
86
  def_node_matcher :sum_map_candidate?, <<~PATTERN
87
- (send
87
+ (call
88
88
  {
89
- (block $(send _ {:map :collect}) ...)
90
- $(send _ {:map :collect} (block_pass _))
89
+ (block $(call _ {:map :collect}) ...)
90
+ $(call _ {:map :collect} (block_pass _))
91
91
  }
92
92
  :sum $_init ?)
93
93
  PATTERN
94
94
 
95
95
  def_node_matcher :sum_with_block_candidate?, <<~PATTERN
96
96
  (block
97
- $(send _ {:inject :reduce} $_init ?)
97
+ $(call _ {:inject :reduce} $_init ?)
98
98
  (args (arg $_acc) (arg $_elem))
99
99
  $send)
100
100
  PATTERN
@@ -110,6 +110,7 @@ module RuboCop
110
110
  handle_sum_candidate(node)
111
111
  handle_sum_map_candidate(node)
112
112
  end
113
+ alias on_csend on_send
113
114
 
114
115
  def on_block(node)
115
116
  sum_with_block_candidate?(node) do |send, init, var_acc, var_elem, body|
@@ -143,7 +144,7 @@ module RuboCop
143
144
  sum_map_candidate?(node) do |map, init|
144
145
  next if node.block_literal? || node.block_argument?
145
146
 
146
- message = build_sum_map_message(map.method_name, init)
147
+ message = build_sum_map_message(map, init)
147
148
 
148
149
  add_offense(sum_map_range(map, node), message: message) do |corrector|
149
150
  autocorrect_sum_map(corrector, node, map, init)
@@ -178,7 +179,7 @@ module RuboCop
178
179
 
179
180
  corrector.remove(sum_range)
180
181
 
181
- dot = '.' if map.receiver
182
+ dot = map.loc.dot&.source || ''
182
183
  corrector.replace(map_range, "#{dot}#{replacement}")
183
184
  end
184
185
 
@@ -205,10 +206,11 @@ module RuboCop
205
206
  format(msg, good_method: good_method, bad_method: bad_method)
206
207
  end
207
208
 
208
- def build_sum_map_message(method, init)
209
+ def build_sum_map_message(send_node, init)
209
210
  sum_method = build_good_method(init)
210
211
  good_method = "#{sum_method} { ... }"
211
- bad_method = "#{method} { ... }.#{sum_method}"
212
+ dot = send_node.loc.dot&.source || '.'
213
+ bad_method = "#{send_node.method_name} { ... }#{dot}#{sum_method}"
212
214
  format(MSG, good_method: good_method, bad_method: bad_method)
213
215
  end
214
216
 
@@ -39,6 +39,7 @@ module RuboCop
39
39
  def on_send(node)
40
40
  check(node)
41
41
  end
42
+ alias on_csend on_send
42
43
 
43
44
  def on_block(node)
44
45
  check(node)
@@ -49,6 +50,8 @@ module RuboCop
49
50
 
50
51
  def check(node)
51
52
  times_map_call(node) do |map_or_collect, count|
53
+ next unless handleable_receiver?(node)
54
+
52
55
  add_offense(node, message: message(map_or_collect, count)) do |corrector|
53
56
  replacement = "Array.new(#{count.source}#{map_or_collect.arguments.map { |arg| ", #{arg.source}" }.join})"
54
57
 
@@ -57,6 +60,13 @@ module RuboCop
57
60
  end
58
61
  end
59
62
 
63
+ def handleable_receiver?(node)
64
+ receiver = node.receiver.receiver
65
+ return true if receiver.literal? && (receiver.int_type? || receiver.float_type?)
66
+
67
+ node.receiver.dot?
68
+ end
69
+
60
70
  def message(map_or_collect, count)
61
71
  template = if count.literal?
62
72
  "#{MESSAGE}."
@@ -67,8 +77,10 @@ module RuboCop
67
77
  end
68
78
 
69
79
  def_node_matcher :times_map_call, <<~PATTERN
70
- {({block numblock} $(send (send $!nil? :times) {:map :collect}) ...)
71
- $(send (send $!nil? :times) {:map :collect} (block_pass ...))}
80
+ {
81
+ ({block numblock} $(call (call $!nil? :times) {:map :collect}) ...)
82
+ $(call (call $!nil? :times) {:map :collect} (block_pass ...))
83
+ }
72
84
  PATTERN
73
85
  end
74
86
  end
@@ -15,8 +15,8 @@ module RuboCop
15
15
  #
16
16
  # @example
17
17
  # # bad
18
- # ''.dup
19
- # "something".dup
18
+ # ''.dup # when Ruby 3.2 or lower
19
+ # "something".dup # when Ruby 3.2 or lower
20
20
  # String.new
21
21
  # String.new('')
22
22
  # String.new('something')
@@ -26,6 +26,9 @@ module RuboCop
26
26
  # +''
27
27
  class UnfreezeString < Base
28
28
  extend AutoCorrector
29
+ extend TargetRubyVersion
30
+
31
+ minimum_target_ruby_version 2.3
29
32
 
30
33
  MSG = 'Use unary plus to get an unfrozen string literal.'
31
34
  RESTRICT_ON_SEND = %i[dup new].freeze
@@ -42,7 +45,7 @@ module RuboCop
42
45
  PATTERN
43
46
 
44
47
  def on_send(node)
45
- return unless dup_string?(node) || string_new?(node)
48
+ return unless (dup_string?(node) && target_ruby_version <= 3.2) || string_new?(node)
46
49
 
47
50
  add_offense(node) do |corrector|
48
51
  string_value = "+#{string_value(node)}"
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Performance
5
5
  # This module holds the RuboCop Performance version information.
6
6
  module Version
7
- STRING = '1.19.0'
7
+ STRING = '1.20.0'
8
8
 
9
9
  def self.document_version
10
10
  STRING.match('\d+\.\d+').to_s
@@ -9,3 +9,11 @@ require_relative 'rubocop/performance/inject'
9
9
  RuboCop::Performance::Inject.defaults!
10
10
 
11
11
  require_relative 'rubocop/cop/performance_cops'
12
+
13
+ RuboCop::Cop::Lint::UnusedMethodArgument.singleton_class.prepend(
14
+ Module.new do
15
+ def autocorrect_incompatible_with
16
+ super.push(RuboCop::Cop::Performance::BlockGivenWithExplicitBlock)
17
+ end
18
+ end
19
+ )
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-performance
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.19.0
4
+ version: 1.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2023-08-13 00:00:00.000000000 Z
13
+ date: 2023-12-16 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rubocop
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - ">="
20
20
  - !ruby/object:Gem::Version
21
- version: 1.7.0
21
+ version: 1.48.1
22
22
  - - "<"
23
23
  - !ruby/object:Gem::Version
24
24
  version: '2.0'
@@ -28,7 +28,7 @@ dependencies:
28
28
  requirements:
29
29
  - - ">="
30
30
  - !ruby/object:Gem::Version
31
- version: 1.7.0
31
+ version: 1.48.1
32
32
  - - "<"
33
33
  - !ruby/object:Gem::Version
34
34
  version: '2.0'
@@ -38,14 +38,20 @@ dependencies:
38
38
  requirements:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: 0.4.0
41
+ version: 1.30.0
42
+ - - "<"
43
+ - !ruby/object:Gem::Version
44
+ version: '2.0'
42
45
  type: :runtime
43
46
  prerelease: false
44
47
  version_requirements: !ruby/object:Gem::Requirement
45
48
  requirements:
46
49
  - - ">="
47
50
  - !ruby/object:Gem::Version
48
- version: 0.4.0
51
+ version: 1.30.0
52
+ - - "<"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
49
55
  description: |
50
56
  A collection of RuboCop cops to check for performance optimizations
51
57
  in Ruby code.
@@ -124,7 +130,7 @@ metadata:
124
130
  homepage_uri: https://docs.rubocop.org/rubocop-performance/
125
131
  changelog_uri: https://github.com/rubocop/rubocop-performance/blob/master/CHANGELOG.md
126
132
  source_code_uri: https://github.com/rubocop/rubocop-performance/
127
- documentation_uri: https://docs.rubocop.org/rubocop-performance/1.19/
133
+ documentation_uri: https://docs.rubocop.org/rubocop-performance/1.20/
128
134
  bug_tracker_uri: https://github.com/rubocop/rubocop-performance/issues
129
135
  rubygems_mfa_required: 'true'
130
136
  post_install_message:
@@ -142,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
148
  - !ruby/object:Gem::Version
143
149
  version: '0'
144
150
  requirements: []
145
- rubygems_version: 3.5.0.dev
151
+ rubygems_version: 3.1.6
146
152
  signing_key:
147
153
  specification_version: 4
148
154
  summary: Automatic performance checking tool for Ruby code.