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

Style/SafeNavigation cop crashes when auto correct #3510

Closed
pocke opened this issue Sep 19, 2016 · 6 comments · Fixed by #3517
Closed

Style/SafeNavigation cop crashes when auto correct #3510

pocke opened this issue Sep 19, 2016 · 6 comments · Fixed by #3517
Labels

Comments

@pocke
Copy link
Collaborator

pocke commented Sep 19, 2016

cc: @rrosenblum

Expected behavior

Don't crash

Actual behavior

RuboCop crashes.

Steps to reproduce the problem

Put the following files.

test.rb

if foo
  foo.bar
end

.rubocop.yml

AllCops:
  TargetRubyVersion: 2.3

And run RuboCop with auto correction.

$ rubocop -d -a --only Style/SafeNavigation
For /tmp/tmp.GoBYI5sfic: configuration from /tmp/tmp.GoBYI5sfic/.rubocop.yml
Default configuration from /home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.43.0/config/default.yml
Inheriting configuration from /home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.43.0/config/enabled.yml
Inheriting configuration from /home/pocke/.gem/ruby/2.3.0/gems/rubocop-0.43.0/config/disabled.yml
Inspecting 1 file
Scanning /tmp/tmp.GoBYI5sfic/test.rb
E

Offenses:

test.rb:1:1: C: [Corrected] Style/SafeNavigation: Use safe navigation (&.) instead of checking if an object exists before calling the method.
if foo ...
^^^^^^
test.rb:3:1: E: unexpected token $end
(Using Ruby 2.3 parser; configure using TargetRubyVersion parameter, under AllCops)

1 file inspected, 2 offenses detected, 1 offense corrected
Finished in 0.0491263820003951 seconds

$ cat test.rb
if foo
  foo&.bar

RuboCop version

$ rubocop -V
0.43.0 (using Parser 2.3.1.3, running on ruby 2.3.1 x86_64-linux)
@dreyks
Copy link
Contributor

dreyks commented Sep 19, 2016

Additional examples of incorrect auto-correct (duh!)

  • !a || a.empty? and a.nil? || a.empty? are corrected into a&.empty?
  • a ? a.b : 'whatever' is corrected to a ? a&.b
  • Same with multiline if
if a
  a.b c
else
  'whatever'
end

is corrected into

if a
  a&.b c
# and that's all, rest is simply wiped

First correction results in broken logic, second and third corrections result in syntax errors

@bbatsov bbatsov added the bug label Sep 19, 2016
@rrosenblum
Copy link
Contributor

Thanks for the bug report. I think that I have an easy fix for the first issue. The other examples will take a little longer to fix, but I don't expect them to be too difficult to fix.

@rrosenblum
Copy link
Contributor

It looks like github auto-linked up my progress on this change since I reused the branch name.

I have a quick solution for @pocke's original request:

if foo
  foo.bar
end

The easiest solution is to not register an offense for non modifier if statements. I would like to spend a little more time on this and register an offense for simple if statement, and not register an offense for more complicated ones.

# register an offense for this
if foo
  foo.bar
end

# allow
if foo
  foo.bar
  baz
end

# allow
if foo
  foo.bar
else
  something
end

@dreyks I think that the examples that you provided !a || a.empty? will warrant a configuration setting. The code in question will work in most cases with safe navigation, but could have some unintended side effects because it will not return the exact same result.

# this is questionable with safe navigation
def something?
  !a || a.empty? # this will always return true or false
end

def something?
  a&.empty? # this will return true, false, or nil
end

# this works fine with safe navigation because nil will be treated as false
something if !a || a.empty?

@dreyks
Copy link
Contributor

dreyks commented Sep 19, 2016

The thing is if a variable is nil its empty? is also nil:

before

def do_something(data = nil)
  return if !data || data.empty?

  p 'doing stuff'
end

do_something # => does not output anything

after

def do_something(data = nil)
  return if data&.empty?

  p 'doing stuff'
end

do_something # => outputs "doing stuff"

@rrosenblum
Copy link
Contributor

You are correct. I will remove the checks for || and make a configuration for && for the reasons listed before.

@basex
Copy link

basex commented Sep 25, 2016

Might be better to cut a release since so many people are reporting the same problem.

mikezter added a commit to mikezter/rubocop that referenced this issue Sep 28, 2016
* bbatsov/master: (80 commits)
  [Fix rubocop#3540] Make `Style/GuardClause` register offense for instance & singleton methods
  [Fix rubocop#3436] issue related to Rails/SaveBang when returning non-bang call from the parent method
  Allow `#to_yml` to produce single-quoted strings
  Add support for StyleGuideBaseURL and update rules
  Add spec for the existing style guide URL implementation
  Fix the changelog
  Edited regular expression for normal case to fix issues rubocop#3514 and rubocop#3516 (rubocop#3524)
  Add a rake task for generation a new cop (rubocop#3533)
  [Fix rubocop#3510] Various bug fixes for SafeNavigation (rubocop#3517)
  [Fix rubocop#3512] Change error message of `Lint/UnneededSplatExpansion` for array (rubocop#3526)
  Fix false positive in `Lint/AssignmentInCondition` (rubocop#3520) (rubocop#3529)
  Rename a mismatched filename (rubocop#3523)
  Fix a broken changelog entry
  [Fix rubocop#3511] Style/TernaryParentheses false positive (rubocop#3513)
  Fix the release notes for 0.43
  Cut 0.43.0
  [Fix rubocop#3462] Don't flag single-line methods
  Fix false negatives in `Rails/NotNullColumn` cop (rubocop#3508)
  Remove unused doubled methods (rubocop#3509)
  [Fix rubocop#3485] Make OneLineConditional cop ignore empty else (rubocop#3487)
  ...
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.

5 participants