diff --git a/changelog/change_string_include_handle_not_match.md b/changelog/change_string_include_handle_not_match.md new file mode 100644 index 0000000000..11cf0c2eae --- /dev/null +++ b/changelog/change_string_include_handle_not_match.md @@ -0,0 +1 @@ +* [#318](https://github.com/rubocop/rubocop-performance/issues/318): Extend `Performance/StringInclude` to handle `!~`. ([@fatkodima][]) diff --git a/lib/rubocop/cop/performance/string_include.rb b/lib/rubocop/cop/performance/string_include.rb index c3d8dcf30a..162708c172 100644 --- a/lib/rubocop/cop/performance/string_include.rb +++ b/lib/rubocop/cop/performance/string_include.rb @@ -22,11 +22,11 @@ module Performance 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 + MSG = 'Use `%sString#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 $!nil? {:match :=~ :!~ :match?} (regexp (str $#literal?) (regopt))) (send (regexp (str $#literal?) (regopt)) {:match :match?} $str) (match-with-lvasgn (regexp (str $#literal?) (regopt)) $_)} PATTERN @@ -34,11 +34,14 @@ class StringInclude < Base def on_send(node) return unless (receiver, regex_str = redundant_regex?(node)) - add_offense(node) do |corrector| + negation = node.send_type? && node.method?(:!~) + message = format(MSG, negation: ('!' if negation)) + + add_offense(node, message: message) 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)})" + new_source = "#{'!' if negation}#{receiver.source}.include?(#{to_string_literal(regex_str)})" corrector.replace(node.source_range, new_source) end diff --git a/spec/rubocop/cop/performance/string_include_spec.rb b/spec/rubocop/cop/performance/string_include_spec.rb index 1ca5ada505..f3c5946452 100644 --- a/spec/rubocop/cop/performance/string_include_spec.rb +++ b/spec/rubocop/cop/performance/string_include_spec.rb @@ -157,4 +157,15 @@ it 'allows argument of `match?` is not a string literal' do expect_no_offenses('/ /.match?(content_as_symbol)') end + + it 'registers an offense and corrects when using `!~`' do + expect_offense(<<~RUBY) + str !~ /abc/ + ^^^^^^^^^^^^ Use `!String#include?` instead of a regex match with literal-only pattern. + RUBY + + expect_correction(<<~RUBY) + !str.include?('abc') + RUBY + end end