Skip to content

Commit

Permalink
Use Cop::Base API for Performance department
Browse files Browse the repository at this point in the history
Follow rubocop/rubocop#7868.

This PR uses `Cop::Base` API for `Performance` department's cops.
  • Loading branch information
MarttiCheng committed Aug 4, 2020
1 parent 05634f1 commit 87fa02b
Show file tree
Hide file tree
Showing 39 changed files with 392 additions and 524 deletions.
17 changes: 6 additions & 11 deletions lib/rubocop/cop/performance/ancestors_include.rb
Expand Up @@ -13,8 +13,9 @@ module Performance
# # good
# A <= B
#
class AncestorsInclude < Cop
class AncestorsInclude < Base
include RangeHelp
extend AutoCorrector

MSG = 'Use `<=` instead of `ancestors.include?`.'

Expand All @@ -23,22 +24,16 @@ class AncestorsInclude < Cop
PATTERN

def on_send(node)
return unless ancestors_include_candidate?(node)
return unless (subclass, superclass = ancestors_include_candidate?(node))

location_of_ancestors = node.children[0].loc.selector.begin_pos
end_location = node.loc.selector.end_pos
range = range_between(location_of_ancestors, end_location)

add_offense(node, location: range)
end

def autocorrect(node)
ancestors_include_candidate?(node) do |subclass, superclass|
lambda do |corrector|
subclass_source = subclass ? subclass.source : 'self'
add_offense(range) do |corrector|
subclass_source = subclass ? subclass.source : 'self'

corrector.replace(node, "#{subclass_source} <= #{superclass.source}")
end
corrector.replace(node, "#{subclass_source} <= #{superclass.source}")
end
end
end
Expand Down
19 changes: 7 additions & 12 deletions lib/rubocop/cop/performance/big_decimal_with_numeric_argument.rb
Expand Up @@ -16,26 +16,21 @@ module Performance
# BigDecimal('1', 2)
# BigDecimal('1.2', 3, exception: true)
#
class BigDecimalWithNumericArgument < Cop
class BigDecimalWithNumericArgument < Base
extend AutoCorrector

MSG = 'Convert numeric argument to string before passing to `BigDecimal`.'

def_node_matcher :big_decimal_with_numeric_argument?, <<~PATTERN
(send nil? :BigDecimal $numeric_type? ...)
PATTERN

def on_send(node)
big_decimal_with_numeric_argument?(node) do |numeric|
next if numeric.float_type? && specifies_precision?(node)

add_offense(node, location: numeric.source_range)
end
end
return unless (numeric = big_decimal_with_numeric_argument?(node))
return if numeric.float_type? && specifies_precision?(node)

def autocorrect(node)
big_decimal_with_numeric_argument?(node) do |numeric|
lambda do |corrector|
corrector.wrap(numeric, "'", "'")
end
add_offense(numeric.source_range) do |corrector|
corrector.wrap(numeric, "'", "'")
end
end

Expand Down
26 changes: 8 additions & 18 deletions lib/rubocop/cop/performance/bind_call.rb
Expand Up @@ -19,8 +19,9 @@ module Performance
# # good
# umethod.bind_call(obj, foo, bar)
#
class BindCall < Cop
class BindCall < Base
include RangeHelp
extend AutoCorrector
extend TargetRubyVersion

minimum_target_ruby_version 2.7
Expand All @@ -37,28 +38,17 @@ class BindCall < Cop
PATTERN

def on_send(node)
bind_with_call_method?(node) do |receiver, bind_arg, call_args_node|
range = correction_range(receiver, node)

call_args = build_call_args(call_args_node)

message = message(bind_arg.source, call_args)

add_offense(node, location: range, message: message)
end
end

def autocorrect(node)
receiver, bind_arg, call_args_node = bind_with_call_method?(node)
return unless (receiver, bind_arg, call_args_node = bind_with_call_method?(node))

range = correction_range(receiver, node)

call_args = build_call_args(call_args_node)
call_args = ", #{call_args}" unless call_args.empty?
message = message(bind_arg.source, call_args)

add_offense(range, message: message) do |corrector|
call_args = ", #{call_args}" unless call_args.empty?

replacement_method = "bind_call(#{bind_arg.source}#{call_args})"
replacement_method = "bind_call(#{bind_arg.source}#{call_args})"

lambda do |corrector|
corrector.replace(range, replacement_method)
end
end
Expand Down
5 changes: 3 additions & 2 deletions lib/rubocop/cop/performance/caller.rb
Expand Up @@ -18,7 +18,7 @@ module Performance
# caller(1..1).first
# caller_locations(2..2).first
# caller_locations(1..1).first
class Caller < Cop
class Caller < Base
MSG_BRACE = 'Use `%<method>s(%<n>d..%<n>d).first`' \
' instead of `%<method>s[%<m>d]`.'
MSG_FIRST = 'Use `%<method>s(%<n>d..%<n>d).first`' \
Expand All @@ -41,7 +41,8 @@ class Caller < Cop
def on_send(node)
return unless caller_with_scope_method?(node)

add_offense(node)
message = message(node)
add_offense(node, message: message)
end

private
Expand Down
29 changes: 18 additions & 11 deletions lib/rubocop/cop/performance/case_when_splat.rb
Expand Up @@ -53,9 +53,10 @@ module Performance
# when 5
# baz
# end
class CaseWhenSplat < Cop
class CaseWhenSplat < Base
include Alignment
include RangeHelp
extend AutoCorrector

MSG = 'Reordering `when` conditions with a splat to the end ' \
'of the `when` branches can improve performance.'
Expand All @@ -66,24 +67,30 @@ def on_case(case_node)
when_conditions = case_node.when_branches.flat_map(&:conditions)

splat_offenses(when_conditions).reverse_each do |condition|
range = condition.parent.loc.keyword.join(condition.source_range)
next if ignored_node?(condition.parent)

ignore_node(condition.parent)
variable, = *condition
message = variable.array_type? ? ARRAY_MSG : MSG
add_offense(condition.parent, location: range, message: message)
add_offense(range(condition), message: message) do |corrector|
autocorrect(corrector, condition.parent)
end
end
end

def autocorrect(when_node)
lambda do |corrector|
if needs_reorder?(when_node)
reorder_condition(corrector, when_node)
else
inline_fix_branch(corrector, when_node)
end
private

def autocorrect(corrector, when_node)
if needs_reorder?(when_node)
reorder_condition(corrector, when_node)
else
inline_fix_branch(corrector, when_node)
end
end

private
def range(node)
node.parent.loc.keyword.join(node.source_range)
end

def replacement(conditions)
reordered = conditions.partition(&:splat_type?).reverse
Expand Down
32 changes: 12 additions & 20 deletions lib/rubocop/cop/performance/casecmp.rb
Expand Up @@ -19,7 +19,9 @@ module Performance
# # good
# str.casecmp('ABC').zero?
# 'abc'.casecmp(str).zero?
class Casecmp < Cop
class Casecmp < Base
extend AutoCorrector

MSG = 'Use `%<good>s` instead of `%<bad>s`.'
CASE_METHODS = %i[downcase upcase].freeze

Expand Down Expand Up @@ -48,21 +50,13 @@ def on_send(node)
return unless downcase_eq(node) || eq_downcase(node)
return unless (parts = take_method_apart(node))

_, _, arg, variable = parts
_receiver, method, arg, variable = parts
good_method = build_good_method(arg, variable)

add_offense(
node,
message: format(MSG, good: good_method, bad: node.source)
)
end

def autocorrect(node)
return unless (parts = take_method_apart(node))

receiver, method, arg, variable = parts

correction(node, receiver, method, arg, variable)
message = format(MSG, good: good_method, bad: node.source)
add_offense(node, message: message) do |corrector|
correction(corrector, node, method, arg, variable)
end
end

private
Expand All @@ -84,14 +78,12 @@ def take_method_apart(node)
[receiver, method, arg, variable]
end

def correction(node, _receiver, method, arg, variable)
lambda do |corrector|
corrector.insert_before(node.loc.expression, '!') if method == :!=
def correction(corrector, node, method, arg, variable)
corrector.insert_before(node.loc.expression, '!') if method == :!=

replacement = build_good_method(arg, variable)
replacement = build_good_method(arg, variable)

corrector.replace(node.loc.expression, replacement)
end
corrector.replace(node.loc.expression, replacement)
end

def build_good_method(arg, variable)
Expand Down
14 changes: 4 additions & 10 deletions lib/rubocop/cop/performance/chain_array_allocation.rb
Expand Up @@ -20,7 +20,7 @@ module Performance
# array.flatten!
# array.map! { |x| x.downcase }
# array
class ChainArrayAllocation < Cop
class ChainArrayAllocation < Base
include RangeHelp

# These methods return a new array but only sometimes. They must be
Expand Down Expand Up @@ -61,15 +61,9 @@ class ChainArrayAllocation < Cop

def on_send(node)
flat_map_candidate?(node) do |fm, sm, _|
range = range_between(
node.loc.dot.begin_pos,
node.source_range.end_pos
)
add_offense(
node,
location: range,
message: format(MSG, method: fm, second_method: sm)
)
range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)

add_offense(range, message: format(MSG, method: fm, second_method: sm))
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/performance/collection_literal_in_loop.rb
Expand Up @@ -31,7 +31,7 @@ module Performance
# ADMIN_ROLES.include?(user.role)
# end
#
class CollectionLiteralInLoop < Cop
class CollectionLiteralInLoop < Base
MSG = 'Avoid immutable %<literal_class>s literals in loops. '\
'It is better to extract it into a local variable or a constant.'

Expand Down
31 changes: 10 additions & 21 deletions lib/rubocop/cop/performance/compare_with_block.rb
Expand Up @@ -23,8 +23,9 @@ module Performance
# array.max_by(&:foo)
# array.min_by(&:foo)
# array.sort_by { |a| a[:foo] }
class CompareWithBlock < Cop
class CompareWithBlock < Base
include RangeHelp
extend AutoCorrector

MSG = 'Use `%<compare_method>s_by%<instead>s` instead of ' \
'`%<compare_method>s { |%<var_a>s, %<var_b>s| %<str_a>s ' \
Expand All @@ -51,27 +52,15 @@ def on_block(node)

range = compare_range(send, node)

add_offense(
node,
location: range,
message: message(send, method, var_a, var_b, args_a)
)
end
end
end

def autocorrect(node)
lambda do |corrector|
send, var_a, var_b, body = compare?(node)
method, arg, = replaceable_body?(body, var_a, var_b)
replacement =
if method == :[]
"#{send.method_name}_by { |a| a[#{arg.first.source}] }"
else
"#{send.method_name}_by(&:#{method})"
add_offense(range, message: message(send, method, var_a, var_b, args_a)) do |corrector|
replacement = if method == :[]
"#{send.method_name}_by { |a| a[#{args_a.first.source}] }"
else
"#{send.method_name}_by(&:#{method})"
end
corrector.replace(range, replacement)
end
corrector.replace(compare_range(send, node),
replacement)
end
end
end

Expand Down
23 changes: 10 additions & 13 deletions lib/rubocop/cop/performance/count.rb
Expand Up @@ -37,8 +37,9 @@ module Performance
# becomes:
#
# `Model.where(id: [1, 2, 3]).to_a.count { |m| m.method == true }`
class Count < Cop
class Count < Base
include RangeHelp
extend AutoCorrector

MSG = 'Use `count` instead of `%<selector>s...%<counter>s`.'

Expand All @@ -57,29 +58,25 @@ def on_send(node)
selector_node.loc.selector.begin_pos
end

add_offense(node,
location: range,
message: format(MSG, selector: selector,
counter: counter))
add_offense(range, message: format(MSG, selector: selector, counter: counter)) do |corrector|
autocorrect(corrector, node, selector_node, selector)
end
end
end

def autocorrect(node)
selector_node, selector, _counter = count_candidate?(node)
private

def autocorrect(corrector, node, selector_node, selector)
selector_loc = selector_node.loc.selector

return if selector == :reject

range = source_starting_at(node) { |n| n.loc.dot.begin_pos }

lambda do |corrector|
corrector.remove(range)
corrector.replace(selector_loc, 'count')
end
corrector.remove(range)
corrector.replace(selector_loc, 'count')
end

private

def eligible_node?(node)
!(node.parent && node.parent.block_type?)
end
Expand Down

0 comments on commit 87fa02b

Please sign in to comment.