Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorrect Regexp fix for Style/RedundantRegexpArgument with extraneous escaped double-quote #13483

Closed
drsharp opened this issue Nov 21, 2024 · 3 comments · Fixed by #13485
Closed
Labels

Comments

@drsharp
Copy link

drsharp commented Nov 21, 2024

We discovered a strange corner-case where a gsub that includes an unnecessarily-escaped double-quote gets autocorrected in a way that affects the gsub. I believe this is an anomaly because Ruby handles /"/ and /\"/ the same way... that is: the extra back-slash is extraneous but the Rubocop rule doesn't handle it as such.

Ruby apparently treats these the same:

irb(main):006:0> "one \" two".gsub(/"/, 'X')
=> "one X two"
irb(main):007:0> "one \" two".gsub(/\"/, 'X')
=> "one X two"

Expected behavior

When passed through Style/RedundantRegexpArgument and autocorrected the following line:

"an escaped \"double-quote\" value".gsub(/\"/, """)

should turn into:

"an escaped \"double-quote\" value".gsub('"', """)

both lines run as normal Ruby output the gsub the same way:

♯ irb
irb(main):001:0> "an escaped \"double-quote\" value".gsub(/\"/, """)
=> "an escaped "double-quote" value"
irb(main):002:0> "an escaped \"double-quote\" value".gsub('"', """)
=> "an escaped "double-quote" value"

Actual behavior

"an escaped \"double-quote\" value".gsub(/\"/, """)

becomes instead:

"an escaped \"double-quote\" value".gsub('\"', """)

(the \ is left in there). And that doesn't process the input string the same way:

irb(main):003:0> "an escaped \"double-quote\" value".gsub('\"', """)
=> "an escaped \"double-quote\" value"

Steps to reproduce the problem

I just created a simple test.rb file with this in it:

#!/usr/bin/env ruby
test_value = 'something with "quotes" around it'
gsub_value = test_value.gsub(/\"/, """)

puts "Test Value: #{test_value.inspect}"
puts "Gsub Value: #{gsub_value.inspect}"

I verified it ran fine and the output was as expected:

♯ ruby test.rb
Test Value: "something with \"quotes\" around it"
Gsub Value: "something with "quotes" around it"

I then ran the rubocop with autocorrect:

♯ rubocop test.rb --autocorrect
Inspecting 1 file
C

Offenses:

test.rb:3:30: C: [Corrected] Style/RedundantRegexpArgument: Use string '\"' as argument instead of regexp /\"/.
gsub_value = test_value.gsub(/\"/, """)
                             ^^^^

which changed it to:

#!/usr/bin/env ruby
test_value = 'something with "quotes" around it'
gsub_value = test_value.gsub('\"', """)

puts "Test Value: #{test_value.inspect}"
puts "Gsub Value: #{gsub_value.inspect}"

But now that runs as:

♯ ruby test.rb                 
Test Value: "something with \"quotes\" around it"
Gsub Value: "something with \"quotes\" around it"

which means the gsub isn't working.

RuboCop version

I originally tested this on 1.64.1 as that is what we are using in our Ruby 2.7.6 main environment:

♯ rubocop -V
1.64.1 (using Parser 3.3.4.2, rubocop-ast 1.32.3, running on ruby 2.7.6) [arm64-darwin23]
  - rubocop-minitest 0.34.5
  - rubocop-performance 1.21.1
  - rubocop-rails 2.23.1

But I also tested it on the latest version in our Ruby 3.3.3 environment and can confirm it fails there as well:

♯ rubocop -V
1.68.0 (using Parser 3.3.4.2, rubocop-ast 1.32.3, analyzing as Ruby 2.7, running on ruby 3.3.3) [arm64-darwin23]
  - rubocop-minitest 0.34.5
  - rubocop-performance 1.22.1
  - rubocop-rails 2.23.1
@drsharp
Copy link
Author

drsharp commented Nov 21, 2024

Hmmm... after a bit more poking around I realized that Style/RedundantRegexpEscape deals with the redundancy.

The issue is that it's run after Style/RedundantRegexpArgument and thus doesn't fix it right. If I start with:

#!/usr/bin/env ruby
test_value = 'something with "quotes" around it'
gsub_value = test_value.gsub(/\"/, """)

puts "Test Value: #{test_value.inspect}"
puts "Gsub Value: #{gsub_value.inspect}"

And run:

♯ rubocop test.rb --autocorrect --only Style/RedundantRegexpEscape                              
Inspecting 1 file
C

Offenses:

test.rb:3:31: C: [Corrected] Style/RedundantRegexpEscape: Redundant escape inside regexp literal
gsub_value = test_value.gsub(/\"/, """)
                              ^^

1 file inspected, 1 offense detected, 1 offense corrected

it corrects that line to be:

gsub_value = test_value.gsub(/"/, """)

(removing the redundant \)

And then if I run:

♯ rubocop test.rb --autocorrect --only Style/RedundantRegexpArgument                      
Inspecting 1 file
C

Offenses:

test.rb:3:30: C: [Corrected] Style/RedundantRegexpArgument: Use string '"' as argument instead of regexp /"/.
gsub_value = test_value.gsub(/"/, """)
                             ^^^

1 file inspected, 1 offense detected, 1 offense corrected

It properly corrects it to now be:

gsub_value = test_value.gsub('"', """)

So I don't know if the best way to deal with this is to add a fix to Style/RedundantRegexpArgument to handle the unusual case of the redundant escape (I can put a PR together for that) or to just make some note of this somewhere. It's definitely a corner case, but it "bit" us when it didn't properly handle this.

If there is an ordering to the cops, maybe Style/RedundantRegexpEscape needs to be run before Style/RedundantRegexpArgument?

@Earlopain
Copy link
Contributor

Great investigative work! Issues where autocorrect from one cop steps on the toes of another crop up every once in a while.

The solution will be to declare them incompatible so that they happen in two passes. You can check out #13369 as a template if you want to make a PR yourself.

@koic koic added the bug label Nov 22, 2024
koic added a commit to koic/rubocop that referenced this issue Nov 22, 2024
…RegexpArgument`

Fixes rubocop#13483.

This PR fixes an incorrect autocorrect for `Style/RedundantRegexpArgument`
when using escaped double quote character.
bbatsov pushed a commit that referenced this issue Nov 22, 2024
…rgument`

Fixes #13483.

This PR fixes an incorrect autocorrect for `Style/RedundantRegexpArgument`
when using escaped double quote character.
@Mohammed-Alanazisa
Copy link

Mohammed-Alanazisa commented Nov 23, 2024

We discovered a strange corner-case where a gsub that includes an unnecessarily-escaped double-quote gets autocorrected in a way that affects the gsub. I believe this is an anomaly because Ruby handles /"/ and /\"/ the same way... that is: the extra back-slash is extraneous but the Rubocop rule doesn't handle it as such.

Ruby apparently treats these the same:

irb(main):006:0> "one \" two".gsub(/"/, 'X')
=> "one X two"
irb(main):007:0> "one \" two".gsub(/\"/, 'X')
=> "one X two"

Expected behavior

When passed through Style/RedundantRegexpArgument and autocorrected the following line:

"an escaped \"double-quote\" value".gsub(/\"/, """)

should turn into:

"an escaped \"double-quote\" value".gsub('"', """)

both lines run as normal Ruby output the gsub the same way:

♯ irb
irb(main):001:0> "an escaped \"double-quote\" value".gsub(/\"/, """)
=> "an escaped "double-quote" value"
irb(main):002:0> "an escaped \"double-quote\" value".gsub('"', """)
=> "an escaped "double-quote" value"

Actual behavior

"an escaped \"double-quote\" value".gsub(/\"/, """)

becomes instead:

"an escaped \"double-quote\" value".gsub('\"', """)

(the \ is left in there). And that doesn't process the input string the same way:

irb(main):003:0> "an escaped \"double-quote\" value".gsub('\"', """)
=> "an escaped \"double-quote\" value"

Steps to reproduce the problem

I just created a simple test.rb file with this in it:

#!/usr/bin/env ruby
test_value = 'something with "quotes" around it'
gsub_value = test_value.gsub(/\"/, """)

puts "Test Value: #{test_value.inspect}"
puts "Gsub Value: #{gsub_value.inspect}"

I verified it ran fine and the output was as expected:

♯ ruby test.rb
Test Value: "something with \"quotes\" around it"
Gsub Value: "something with "quotes" around it"

I then ran the rubocop with autocorrect:

♯ rubocop test.rb --autocorrect
Inspecting 1 file
C

Offenses:

test.rb:3:30: C: [Corrected] Style/RedundantRegexpArgument: Use string '\"' as argument instead of regexp /\"/.
gsub_value = test_value.gsub(/\"/, """)
                             ^^^^

which changed it to:

#!/usr/bin/env ruby
test_value = 'something with "quotes" around it'
gsub_value = test_value.gsub('\"', """)

puts "Test Value: #{test_value.inspect}"
puts "Gsub Value: #{gsub_value.inspect}"

But now that runs as:

♯ ruby test.rb                 
Test Value: "something with \"quotes\" around it"
Gsub Value: "something with \"quotes\" around it"

which means the gsub isn't working.

RuboCop version

I originally tested this on 1.64.1 as that is what we are using in our Ruby 2.7.6 main environment:

♯ rubocop -V
1.64.1 (using Parser 3.3.4.2, rubocop-ast 1.32.3, running on ruby 2.7.6) [arm64-darwin23]
  - rubocop-minitest 0.34.5
  - rubocop-performance 1.21.1
  - rubocop-rails 2.23.1

But I also tested it on the latest version in our Ruby 3.3.3 environment and can confirm it fails there as well:

♯ rubocop -V
1.68.0 (using Parser 3.3.4.2, rubocop-ast 1.32.3, analyzing as Ruby 2.7, running on ruby 3.3.3) [arm64-darwin23]
  - rubocop-minitest 0.34.5
  - rubocop-performance 1.22.1
  - rubocop-rails 2.23.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants