rubocop-performance 1.7.1 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/config/default.yml +18 -7
- data/lib/rubocop/cop/performance/ancestors_include.rb +14 -13
- data/lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb +7 -12
- data/lib/rubocop/cop/performance/bind_call.rb +8 -18
- data/lib/rubocop/cop/performance/caller.rb +3 -2
- data/lib/rubocop/cop/performance/case_when_splat.rb +18 -11
- data/lib/rubocop/cop/performance/casecmp.rb +12 -20
- data/lib/rubocop/cop/performance/chain_array_allocation.rb +4 -10
- data/lib/rubocop/cop/performance/collection_literal_in_loop.rb +140 -0
- data/lib/rubocop/cop/performance/compare_with_block.rb +10 -21
- data/lib/rubocop/cop/performance/count.rb +13 -16
- data/lib/rubocop/cop/performance/delete_prefix.rb +13 -22
- data/lib/rubocop/cop/performance/delete_suffix.rb +13 -22
- data/lib/rubocop/cop/performance/detect.rb +29 -26
- data/lib/rubocop/cop/performance/double_start_end_with.rb +16 -24
- data/lib/rubocop/cop/performance/end_with.rb +8 -13
- data/lib/rubocop/cop/performance/fixed_size.rb +1 -1
- data/lib/rubocop/cop/performance/flat_map.rb +20 -22
- data/lib/rubocop/cop/performance/inefficient_hash_search.rb +13 -14
- data/lib/rubocop/cop/performance/io_readlines.rb +25 -36
- data/lib/rubocop/cop/performance/open_struct.rb +2 -2
- data/lib/rubocop/cop/performance/range_include.rb +7 -6
- data/lib/rubocop/cop/performance/redundant_block_call.rb +11 -6
- data/lib/rubocop/cop/performance/redundant_match.rb +11 -6
- data/lib/rubocop/cop/performance/redundant_merge.rb +18 -17
- data/lib/rubocop/cop/performance/redundant_sort_block.rb +6 -16
- data/lib/rubocop/cop/performance/redundant_string_chars.rb +8 -12
- data/lib/rubocop/cop/performance/regexp_match.rb +20 -20
- data/lib/rubocop/cop/performance/reverse_each.rb +9 -5
- data/lib/rubocop/cop/performance/reverse_first.rb +4 -10
- data/lib/rubocop/cop/performance/size.rb +6 -6
- data/lib/rubocop/cop/performance/sort_reverse.rb +6 -15
- data/lib/rubocop/cop/performance/squeeze.rb +6 -10
- data/lib/rubocop/cop/performance/start_with.rb +8 -13
- data/lib/rubocop/cop/performance/string_include.rb +9 -13
- data/lib/rubocop/cop/performance/string_replacement.rb +23 -27
- data/lib/rubocop/cop/performance/sum.rb +129 -0
- data/lib/rubocop/cop/performance/times_map.rb +11 -18
- data/lib/rubocop/cop/performance/unfreeze_string.rb +1 -1
- data/lib/rubocop/cop/performance/uri_default_parser.rb +6 -12
- data/lib/rubocop/cop/performance_cops.rb +2 -0
- data/lib/rubocop/performance/version.rb +1 -1
- metadata +6 -4
@@ -36,7 +36,9 @@ module RuboCop
|
|
36
36
|
# { a: 1, b: 2 }.has_value?('garbage')
|
37
37
|
# h = { a: 1, b: 2 }; h.value?(nil)
|
38
38
|
#
|
39
|
-
class InefficientHashSearch <
|
39
|
+
class InefficientHashSearch < Base
|
40
|
+
extend AutoCorrector
|
41
|
+
|
40
42
|
def_node_matcher :inefficient_include?, <<~PATTERN
|
41
43
|
(send (send $_ {:keys :values}) :include? _)
|
42
44
|
PATTERN
|
@@ -45,19 +47,16 @@ module RuboCop
|
|
45
47
|
inefficient_include?(node) do |receiver|
|
46
48
|
return if receiver.nil?
|
47
49
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
"#{autocorrect_hash_expression(node)}."\
|
59
|
-
"#{autocorrect_method(node)}(#{autocorrect_argument(node)})"
|
60
|
-
)
|
50
|
+
message = message(node)
|
51
|
+
add_offense(node, message: message) do |corrector|
|
52
|
+
# Replace `keys.include?` or `values.include?` with the appropriate
|
53
|
+
# `key?`/`value?` method.
|
54
|
+
corrector.replace(
|
55
|
+
node.loc.expression,
|
56
|
+
"#{autocorrect_hash_expression(node)}."\
|
57
|
+
"#{autocorrect_method(node)}(#{autocorrect_argument(node)})"
|
58
|
+
)
|
59
|
+
end
|
61
60
|
end
|
62
61
|
end
|
63
62
|
|
@@ -24,8 +24,9 @@ module RuboCop
|
|
24
24
|
# file.each_line.find { |l| l.start_with?('#') }
|
25
25
|
# file.each_line { |l| puts l }
|
26
26
|
#
|
27
|
-
class IoReadlines <
|
27
|
+
class IoReadlines < Base
|
28
28
|
include RangeHelp
|
29
|
+
extend AutoCorrector
|
29
30
|
|
30
31
|
MSG = 'Use `%<good>s` instead of `%<bad>s`.'
|
31
32
|
ENUMERABLE_METHODS = (Enumerable.instance_methods + [:each]).freeze
|
@@ -39,34 +40,16 @@ module RuboCop
|
|
39
40
|
PATTERN
|
40
41
|
|
41
42
|
def on_send(node)
|
42
|
-
readlines_on_class?(node)
|
43
|
-
offense(node, enumerable_call, readlines_call)
|
44
|
-
end
|
43
|
+
return unless (captured_values = readlines_on_class?(node) || readlines_on_instance?(node))
|
45
44
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
45
|
+
enumerable_call, readlines_call, receiver = *captured_values
|
46
|
+
|
47
|
+
range = offense_range(enumerable_call, readlines_call)
|
48
|
+
good_method = build_good_method(enumerable_call)
|
49
|
+
bad_method = build_bad_method(enumerable_call)
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
# We cannot safely correct `.readlines` method called on IO/File classes
|
54
|
-
# due to its signature and we are not sure with implicit receiver
|
55
|
-
# if it is called in the context of some instance or mentioned class.
|
56
|
-
return if receiver.nil?
|
57
|
-
|
58
|
-
lambda do |corrector|
|
59
|
-
range = correction_range(enumerable_call, readlines_call)
|
60
|
-
|
61
|
-
if readlines_call.arguments?
|
62
|
-
call_args = build_call_args(readlines_call.arguments)
|
63
|
-
replacement = "each_line(#{call_args})"
|
64
|
-
else
|
65
|
-
replacement = 'each_line'
|
66
|
-
end
|
67
|
-
|
68
|
-
corrector.replace(range, replacement)
|
69
|
-
end
|
51
|
+
add_offense(range, message: format(MSG, good: good_method, bad: bad_method)) do |corrector|
|
52
|
+
autocorrect(corrector, enumerable_call, readlines_call, receiver)
|
70
53
|
end
|
71
54
|
end
|
72
55
|
|
@@ -76,16 +59,22 @@ module RuboCop
|
|
76
59
|
ENUMERABLE_METHODS.include?(node.to_sym)
|
77
60
|
end
|
78
61
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
82
|
-
|
62
|
+
def autocorrect(corrector, enumerable_call, readlines_call, receiver)
|
63
|
+
# We cannot safely correct `.readlines` method called on IO/File classes
|
64
|
+
# due to its signature and we are not sure with implicit receiver
|
65
|
+
# if it is called in the context of some instance or mentioned class.
|
66
|
+
return if receiver.nil?
|
67
|
+
|
68
|
+
range = correction_range(enumerable_call, readlines_call)
|
69
|
+
|
70
|
+
if readlines_call.arguments?
|
71
|
+
call_args = build_call_args(readlines_call.arguments)
|
72
|
+
replacement = "each_line(#{call_args})"
|
73
|
+
else
|
74
|
+
replacement = 'each_line'
|
75
|
+
end
|
83
76
|
|
84
|
-
|
85
|
-
node,
|
86
|
-
location: range,
|
87
|
-
message: format(MSG, good: good_method, bad: bad_method)
|
88
|
-
)
|
77
|
+
corrector.replace(range, replacement)
|
89
78
|
end
|
90
79
|
|
91
80
|
def offense_range(enumerable_call, readlines_call)
|
@@ -27,7 +27,7 @@ module RuboCop
|
|
27
27
|
# end
|
28
28
|
# end
|
29
29
|
#
|
30
|
-
class OpenStruct <
|
30
|
+
class OpenStruct < Base
|
31
31
|
MSG = 'Consider using `Struct` over `OpenStruct` ' \
|
32
32
|
'to optimize the performance.'
|
33
33
|
|
@@ -37,7 +37,7 @@ module RuboCop
|
|
37
37
|
|
38
38
|
def on_send(node)
|
39
39
|
open_struct(node) do
|
40
|
-
add_offense(node
|
40
|
+
add_offense(node.loc.selector)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -24,7 +24,9 @@ module RuboCop
|
|
24
24
|
# # the desired result:
|
25
25
|
#
|
26
26
|
# ('a'..'z').cover?('yellow') # => true
|
27
|
-
class RangeInclude <
|
27
|
+
class RangeInclude < Base
|
28
|
+
extend AutoCorrector
|
29
|
+
|
28
30
|
MSG = 'Use `Range#cover?` instead of `Range#%<bad_method>s`.'
|
29
31
|
|
30
32
|
# TODO: If we traced out assignments of variables to their uses, we
|
@@ -39,12 +41,11 @@ module RuboCop
|
|
39
41
|
def on_send(node)
|
40
42
|
range_include(node) do |bad_method|
|
41
43
|
message = format(MSG, bad_method: bad_method)
|
42
|
-
add_offense(node, location: :selector, message: message)
|
43
|
-
end
|
44
|
-
end
|
45
44
|
|
46
|
-
|
47
|
-
|
45
|
+
add_offense(node.loc.selector, message: message) do |corrector|
|
46
|
+
corrector.replace(node.loc.selector, 'cover?')
|
47
|
+
end
|
48
|
+
end
|
48
49
|
end
|
49
50
|
end
|
50
51
|
end
|
@@ -22,7 +22,9 @@ module RuboCop
|
|
22
22
|
# def another
|
23
23
|
# yield 1, 2, 3
|
24
24
|
# end
|
25
|
-
class RedundantBlockCall <
|
25
|
+
class RedundantBlockCall < Base
|
26
|
+
extend AutoCorrector
|
27
|
+
|
26
28
|
MSG = 'Use `yield` instead of `%<argname>s.call`.'
|
27
29
|
YIELD = 'yield'
|
28
30
|
OPEN_PAREN = '('
|
@@ -47,13 +49,17 @@ module RuboCop
|
|
47
49
|
next unless body
|
48
50
|
|
49
51
|
calls_to_report(argname, body).each do |blockcall|
|
50
|
-
add_offense(blockcall, message: format(MSG, argname: argname))
|
52
|
+
add_offense(blockcall, message: format(MSG, argname: argname)) do |corrector|
|
53
|
+
autocorrect(corrector, blockcall)
|
54
|
+
end
|
51
55
|
end
|
52
56
|
end
|
53
57
|
end
|
54
58
|
|
59
|
+
private
|
60
|
+
|
55
61
|
# offenses are registered on the `block.call` nodes
|
56
|
-
def autocorrect(node)
|
62
|
+
def autocorrect(corrector, node)
|
57
63
|
_receiver, _method, *args = *node
|
58
64
|
new_source = String.new(YIELD)
|
59
65
|
unless args.empty?
|
@@ -67,10 +73,9 @@ module RuboCop
|
|
67
73
|
end
|
68
74
|
|
69
75
|
new_source << CLOSE_PAREN if parentheses?(node) && !args.empty?
|
70
|
-
->(corrector) { corrector.replace(node.source_range, new_source) }
|
71
|
-
end
|
72
76
|
|
73
|
-
|
77
|
+
corrector.replace(node.source_range, new_source)
|
78
|
+
end
|
74
79
|
|
75
80
|
def calls_to_report(argname, body)
|
76
81
|
return [] if blockarg_assigned?(body, argname)
|
@@ -17,7 +17,9 @@ module RuboCop
|
|
17
17
|
# # good
|
18
18
|
# method(str =~ /regex/)
|
19
19
|
# return value unless regex =~ 'str'
|
20
|
-
class RedundantMatch <
|
20
|
+
class RedundantMatch < Base
|
21
|
+
extend AutoCorrector
|
22
|
+
|
21
23
|
MSG = 'Use `=~` in places where the `MatchData` returned by ' \
|
22
24
|
'`#match` will not be used.'
|
23
25
|
|
@@ -37,18 +39,21 @@ module RuboCop
|
|
37
39
|
(!node.value_used? || only_truthiness_matters?(node)) &&
|
38
40
|
!(node.parent && node.parent.block_type?)
|
39
41
|
|
40
|
-
add_offense(node)
|
42
|
+
add_offense(node) do |corrector|
|
43
|
+
autocorrect(corrector, node)
|
44
|
+
end
|
41
45
|
end
|
42
46
|
|
43
|
-
|
47
|
+
private
|
48
|
+
|
49
|
+
def autocorrect(corrector, node)
|
44
50
|
# Regexp#match can take a second argument, but this cop doesn't
|
45
51
|
# register an offense in that case
|
46
52
|
return unless node.first_argument.regexp_type?
|
47
53
|
|
48
|
-
new_source =
|
49
|
-
node.receiver.source + ' =~ ' + node.first_argument.source
|
54
|
+
new_source = "#{node.receiver.source} =~ #{node.first_argument.source}"
|
50
55
|
|
51
|
-
|
56
|
+
corrector.replace(node.source_range, new_source)
|
52
57
|
end
|
53
58
|
end
|
54
59
|
end
|
@@ -24,7 +24,9 @@ module RuboCop
|
|
24
24
|
# # good
|
25
25
|
# hash[:a] = 1
|
26
26
|
# hash[:b] = 2
|
27
|
-
class RedundantMerge <
|
27
|
+
class RedundantMerge < Base
|
28
|
+
extend AutoCorrector
|
29
|
+
|
28
30
|
AREF_ASGN = '%<receiver>s[%<key>s] = %<value>s'
|
29
31
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
30
32
|
|
@@ -44,18 +46,17 @@ module RuboCop
|
|
44
46
|
|
45
47
|
def on_send(node)
|
46
48
|
each_redundant_merge(node) do |redundant_merge_node|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
correct_single_element(node, new_source)
|
49
|
+
message = message(node)
|
50
|
+
add_offense(redundant_merge_node, message: message) do |corrector|
|
51
|
+
redundant_merge_candidate(node) do |receiver, pairs|
|
52
|
+
new_source = to_assignments(receiver, pairs).join("\n")
|
53
|
+
|
54
|
+
if node.parent && pairs.size > 1
|
55
|
+
correct_multiple_elements(corrector, node, node.parent, new_source)
|
56
|
+
else
|
57
|
+
correct_single_element(corrector, node, new_source)
|
58
|
+
end
|
59
|
+
end
|
59
60
|
end
|
60
61
|
end
|
61
62
|
end
|
@@ -98,7 +99,7 @@ module RuboCop
|
|
98
99
|
!EachWithObjectInspector.new(node, receiver).value_used?
|
99
100
|
end
|
100
101
|
|
101
|
-
def correct_multiple_elements(node, parent, new_source)
|
102
|
+
def correct_multiple_elements(corrector, node, parent, new_source)
|
102
103
|
if modifier_flow_control?(parent)
|
103
104
|
new_source = rewrite_with_modifier(node, parent, new_source)
|
104
105
|
node = parent
|
@@ -107,11 +108,11 @@ module RuboCop
|
|
107
108
|
new_source.gsub!(/\n/, padding)
|
108
109
|
end
|
109
110
|
|
110
|
-
|
111
|
+
corrector.replace(node.source_range, new_source)
|
111
112
|
end
|
112
113
|
|
113
|
-
def correct_single_element(node, new_source)
|
114
|
-
|
114
|
+
def correct_single_element(corrector, node, new_source)
|
115
|
+
corrector.replace(node.source_range, new_source)
|
115
116
|
end
|
116
117
|
|
117
118
|
def to_assignments(receiver, pairs)
|
@@ -13,29 +13,19 @@ module RuboCop
|
|
13
13
|
# # good
|
14
14
|
# array.sort
|
15
15
|
#
|
16
|
-
class RedundantSortBlock <
|
16
|
+
class RedundantSortBlock < Base
|
17
17
|
include SortBlock
|
18
|
+
extend AutoCorrector
|
18
19
|
|
19
20
|
MSG = 'Use `sort` instead of `%<bad_method>s`.'
|
20
21
|
|
21
22
|
def on_block(node)
|
22
|
-
|
23
|
-
replaceable_body?(body, var_a, var_b) do
|
24
|
-
range = sort_range(send, node)
|
23
|
+
return unless (send, var_a, var_b, body = sort_with_block?(node))
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
location: range,
|
29
|
-
message: message(var_a, var_b)
|
30
|
-
)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
25
|
+
replaceable_body?(body, var_a, var_b) do
|
26
|
+
range = sort_range(send, node)
|
34
27
|
|
35
|
-
|
36
|
-
sort_with_block?(node) do |send, _var_a, _var_b, _body|
|
37
|
-
lambda do |corrector|
|
38
|
-
range = sort_range(send, node)
|
28
|
+
add_offense(range, message: message(var_a, var_b)) do |corrector|
|
39
29
|
corrector.replace(range, 'sort')
|
40
30
|
end
|
41
31
|
end
|
@@ -39,8 +39,9 @@ module RuboCop
|
|
39
39
|
# str.size
|
40
40
|
# str.empty?
|
41
41
|
#
|
42
|
-
class RedundantStringChars <
|
42
|
+
class RedundantStringChars < Base
|
43
43
|
include RangeHelp
|
44
|
+
extend AutoCorrector
|
44
45
|
|
45
46
|
MSG = 'Use `%<good_method>s` instead of `%<bad_method>s`.'
|
46
47
|
REPLACEABLE_METHODS = %i[[] slice first last take drop length size empty?].freeze
|
@@ -50,21 +51,16 @@ module RuboCop
|
|
50
51
|
PATTERN
|
51
52
|
|
52
53
|
def on_send(node)
|
53
|
-
|
54
|
-
range = offense_range(receiver, node)
|
55
|
-
message = build_message(method, args)
|
56
|
-
add_offense(node, location: range, message: message)
|
57
|
-
end
|
58
|
-
end
|
54
|
+
return unless (receiver, method, args = redundant_chars_call?(node))
|
59
55
|
|
60
|
-
|
61
|
-
|
56
|
+
range = offense_range(receiver, node)
|
57
|
+
message = build_message(method, args)
|
58
|
+
|
59
|
+
add_offense(range, message: message) do |corrector|
|
62
60
|
range = correction_range(receiver, node)
|
63
61
|
replacement = build_good_method(method, args)
|
64
62
|
|
65
|
-
|
66
|
-
corrector.replace(range, replacement)
|
67
|
-
end
|
63
|
+
corrector.replace(range, replacement)
|
68
64
|
end
|
69
65
|
end
|
70
66
|
|
@@ -72,7 +72,9 @@ module RuboCop
|
|
72
72
|
# do_something($~)
|
73
73
|
# end
|
74
74
|
# end
|
75
|
-
class RegexpMatch <
|
75
|
+
class RegexpMatch < Base
|
76
|
+
extend AutoCorrector
|
77
|
+
|
76
78
|
# Constants are included in this list because it is unlikely that
|
77
79
|
# someone will store `nil` as a constant and then use it for comparison
|
78
80
|
TYPES_IMPLEMENTING_MATCH = %i[const regexp str sym].freeze
|
@@ -141,27 +143,28 @@ module RuboCop
|
|
141
143
|
end
|
142
144
|
end
|
143
145
|
|
144
|
-
def autocorrect(node)
|
145
|
-
lambda do |corrector|
|
146
|
-
if match_method?(node) || match_with_int_arg_method?(node)
|
147
|
-
corrector.replace(node.loc.selector, 'match?')
|
148
|
-
elsif match_operator?(node) || match_threequals?(node)
|
149
|
-
recv, oper, arg = *node
|
150
|
-
correct_operator(corrector, recv, arg, oper)
|
151
|
-
elsif match_with_lvasgn?(node)
|
152
|
-
recv, arg = *node
|
153
|
-
correct_operator(corrector, recv, arg)
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
146
|
private
|
159
147
|
|
160
148
|
def check_condition(cond)
|
161
149
|
match_node?(cond) do
|
162
150
|
return if last_match_used?(cond)
|
163
151
|
|
164
|
-
|
152
|
+
message = message(cond)
|
153
|
+
add_offense(cond, message: message) do |corrector|
|
154
|
+
autocorrect(corrector, cond)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def autocorrect(corrector, node)
|
160
|
+
if match_method?(node) || match_with_int_arg_method?(node)
|
161
|
+
corrector.replace(node.loc.selector, 'match?')
|
162
|
+
elsif match_operator?(node) || match_threequals?(node)
|
163
|
+
recv, oper, arg = *node
|
164
|
+
correct_operator(corrector, recv, arg, oper)
|
165
|
+
elsif match_with_lvasgn?(node)
|
166
|
+
recv, arg = *node
|
167
|
+
correct_operator(corrector, recv, arg)
|
165
168
|
end
|
166
169
|
end
|
167
170
|
|
@@ -231,10 +234,7 @@ module RuboCop
|
|
231
234
|
|
232
235
|
def scope_root(node)
|
233
236
|
node.each_ancestor.find do |ancestor|
|
234
|
-
ancestor.def_type? ||
|
235
|
-
ancestor.defs_type? ||
|
236
|
-
ancestor.class_type? ||
|
237
|
-
ancestor.module_type?
|
237
|
+
ancestor.def_type? || ancestor.defs_type? || ancestor.class_type? || ancestor.module_type?
|
238
238
|
end
|
239
239
|
end
|
240
240
|
|