Skip to content

Commit

Permalink
Fix an incorrect auto-correct for `Performance/RedundantSplitRegexpAr…
Browse files Browse the repository at this point in the history
…gument`

Follow rubocop#190.

This PR fixes the following incorrect auto-correct for `Performance/RedundantSplitRegexpArgument`
when using consecutive special string chars.

```console
% cat example.rb
"foo\nbar\nbaz\n".split(/\n\n/)

% bundle exec rubocop example.rb --only Performance/RedundantSplitRegexpArgument -a
Inspecting 1 file
C

Offenses:

example.rb:1:25: C: [Corrected]
Performance/RedundantSplitRegexpArgument: Use string as argument instead of regexp.
"foo\nbar\nbaz\n".split(/\n\n/)
                        ^^^^^^

1 file inspected, 1 offense detected, 1 offense corrected

## Before

```console
% cat example.rb
"foo\nbar\nbaz\n".split("nn")
```

## After

```console
% cat example.rb
"foo\nbar\nbaz\n".split("\n\n")
```
  • Loading branch information
koic committed Jan 26, 2021
1 parent 209a88b commit f0464c9
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 3 deletions.
22 changes: 19 additions & 3 deletions lib/rubocop/cop/performance/redundant_split_regexp_argument.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class RedundantSplitRegexpArgument < Base
MSG = 'Use string as argument instead of regexp.'
RESTRICT_ON_SEND = %i[split].freeze
DETERMINISTIC_REGEX = /\A(?:#{LITERAL_REGEX})+\Z/.freeze
STR_SPECIAL_CHARS = %w[\n \" \' \\ \t \b \f \r].freeze
STR_SPECIAL_CHARS = %w[\n \" \' \\\\ \t \b \f \r].freeze

def_node_matcher :split_call_with_regexp?, <<~PATTERN
{(send !nil? :split {regexp})}
Expand All @@ -40,11 +40,27 @@ def determinist_regexp?(first_argument)
end

def autocorrect(corrector, node)
new_argument = node.first_argument.source[1..-2]
new_argument.delete!('\\') unless STR_SPECIAL_CHARS.include?(new_argument)
new_argument = replacement(node)

corrector.replace(node.first_argument, "\"#{new_argument}\"")
end

def replacement(node)
regexp_content = node.first_argument.content
stack = []
chars = regexp_content.chars.each_with_object([]) do |char, strings|
if stack.empty? && char == '\\'
stack.push(char)
else
strings << "#{stack.pop}#{char}"
end
end
chars.map do |char|
char = char.dup
char.delete!('\\') unless STR_SPECIAL_CHARS.include?(char)
char
end.join
end
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,39 @@
RUBY
end

it 'registers an offense when the method is split and corrects correctly consecutive special string chars' do
expect_offense(<<~RUBY)
"foo\\n\\nbar\\n\\nbaz\\n\\n".split(/\\n\\n/)
^^^^^^ Use string as argument instead of regexp.
RUBY

expect_correction(<<~RUBY)
"foo\\n\\nbar\\n\\nbaz\\n\\n".split("\\n\\n")
RUBY
end

it 'registers an offense when the method is split and corrects correctly consecutive backslash escape chars' do
expect_offense(<<~RUBY)
"foo\\\\\\.bar".split(/\\\\\\./)
^^^^^^ Use string as argument instead of regexp.
RUBY

expect_correction(<<~RUBY)
"foo\\\\\\.bar".split("\\\\\.")
RUBY
end

it 'registers an offense when the method is split and corrects correctly complex special string chars' do
expect_offense(<<~RUBY)
"foo\\nbar\\nbaz\\n".split(/foo\\n\\.\\n/)
^^^^^^^^^^^ Use string as argument instead of regexp.
RUBY

expect_correction(<<~RUBY)
"foo\\nbar\\nbaz\\n".split("foo\\n.\\n")
RUBY
end

it 'registers an offense when the method is split' do
expect_offense(<<~RUBY)
'a,b,c'.split(/,/)
Expand Down

0 comments on commit f0464c9

Please sign in to comment.