forked from rubocop/rubocop-performance
-
Notifications
You must be signed in to change notification settings - Fork 0
/
string_include.rb
56 lines (47 loc) · 1.65 KB
/
string_include.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# frozen_string_literal: true
module RuboCop
module Cop
module Performance
# This cop identifies unnecessary use of a regex where
# `String#include?` would suffice.
#
# This cop's offenses are not safe to auto-correct if a receiver is nil.
#
# @example
# # bad
# 'abc'.match?(/ab/)
# /ab/.match?('abc')
# 'abc' =~ /ab/
# /ab/ =~ 'abc'
# 'abc'.match(/ab/)
# /ab/.match('abc')
#
# # good
# 'abc'.include?('ab')
class StringInclude < Base
extend AutoCorrector
MSG = 'Use `String#include?` instead of a regex match with literal-only pattern.'
RESTRICT_ON_SEND = %i[match =~ match?].freeze
def_node_matcher :redundant_regex?, <<~PATTERN
{(send $!nil? {:match :=~ :match?} (regexp (str $#literal?) (regopt)))
(send (regexp (str $#literal?) (regopt)) {:match :match?} $str)
(match-with-lvasgn (regexp (str $#literal?) (regopt)) $_)}
PATTERN
def on_send(node)
return unless (receiver, regex_str = redundant_regex?(node))
add_offense(node) do |corrector|
receiver, regex_str = regex_str, receiver if receiver.is_a?(String)
regex_str = interpret_string_escapes(regex_str)
new_source = "#{receiver.source}.include?(#{to_string_literal(regex_str)})"
corrector.replace(node.source_range, new_source)
end
end
alias on_match_with_lvasgn on_send
private
def literal?(regex_str)
regex_str.match?(/\A#{Util::LITERAL_REGEX}+\z/o)
end
end
end
end
end