diff --git a/changelog/fix_a_false_negative_for_performance_redundant_string_chars.md b/changelog/fix_a_false_negative_for_performance_redundant_string_chars.md new file mode 100644 index 0000000000..1b97e738d1 --- /dev/null +++ b/changelog/fix_a_false_negative_for_performance_redundant_string_chars.md @@ -0,0 +1 @@ +* [#313](https://github.com/rubocop/rubocop-performance/issues/313): Fix a false negative for `Performance/RedundantStringChars` when using `str.chars.last` without argument. ([@koic][]) diff --git a/lib/rubocop/cop/performance/redundant_string_chars.rb b/lib/rubocop/cop/performance/redundant_string_chars.rb index 000d887ced..f6617068ba 100644 --- a/lib/rubocop/cop/performance/redundant_string_chars.rb +++ b/lib/rubocop/cop/performance/redundant_string_chars.rb @@ -9,6 +9,7 @@ module Performance # # bad # str.chars[0..2] # str.chars.slice(0..2) + # str.chars.last # # # good # str[0..2].chars @@ -20,6 +21,7 @@ module Performance # # good # str[0] # str[0...2].chars + # str[-1] # # # bad # str.chars.take(2) @@ -33,9 +35,8 @@ module Performance # str.size # str.empty? # - # # For example, if the receiver is a blank string, it will be incompatible. + # # For example, if the receiver is an empty string, it will be incompatible. # # If a negative value is specified for the receiver, `nil` is returned. - # str.chars.last # Incompatible with `str[-1]`. # str.chars.last(2) # Incompatible with `str[-2..-1].chars`. # str.chars.drop(2) # Incompatible with `str[2..-1].chars`. # @@ -44,7 +45,7 @@ class RedundantStringChars < Base extend AutoCorrector MSG = 'Use `%s` instead of `%s`.' - RESTRICT_ON_SEND = %i[[] slice first take length size empty?].freeze + RESTRICT_ON_SEND = %i[[] slice first last take length size empty?].freeze def_node_matcher :redundant_chars_call?, <<~PATTERN (send $(send _ :chars) $_ $...) @@ -52,6 +53,7 @@ class RedundantStringChars < Base def on_send(node) return unless (receiver, method, args = redundant_chars_call?(node)) + return if method == :last && !args.empty? range = offense_range(receiver, node) message = build_message(method, args) @@ -86,6 +88,8 @@ def build_good_method(method, args) "[#{build_call_args(args)}].chars" when :[], :first build_good_method_for_brackets_or_first_method(method, args) + when :last + '[-1]' when :take "[0...#{args.first.source}].chars" else diff --git a/spec/rubocop/cop/performance/redundant_string_chars_spec.rb b/spec/rubocop/cop/performance/redundant_string_chars_spec.rb index a5208110f5..920bc6d914 100644 --- a/spec/rubocop/cop/performance/redundant_string_chars_spec.rb +++ b/spec/rubocop/cop/performance/redundant_string_chars_spec.rb @@ -67,9 +67,14 @@ RUBY end - it 'does not register an offense when using `str.chars.last`' do - expect_no_offenses(<<~RUBY) + it 'registers an offense and corrects when using `str.chars.last`' do + expect_offense(<<~RUBY) str.chars.last + ^^^^^^^^^^ Use `[-1]` instead of `chars.last`. + RUBY + + expect_correction(<<~RUBY) + str[-1] RUBY end