diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ce6cd87336..de739cfefb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ * [#8572](https://github.com/rubocop-hq/rubocop/issues/8572): Fix a false positive for `Style/RedundantParentheses` when parentheses are used like method argument parentheses. ([@koic][]) * [#8653](https://github.com/rubocop-hq/rubocop/pull/8653): Fix a false positive for `Layout/DefEndAlignment` when using refinements and `private def`. ([@koic][]) * [#8655](https://github.com/rubocop-hq/rubocop/pull/8655): Fix a false positive for `Style/ClassAndModuleChildren` when using cbase class name. ([@koic][]) +* [#8654](https://github.com/rubocop-hq/rubocop/pull/8654): Fix a false positive for `Style/SafeNavigation` when checking `foo&.empty?` in a conditional. ([@koic][]) ### Changes diff --git a/docs/modules/ROOT/pages/cops_style.adoc b/docs/modules/ROOT/pages/cops_style.adoc index d1a84bdd840..72482f7212a 100644 --- a/docs/modules/ROOT/pages/cops_style.adoc +++ b/docs/modules/ROOT/pages/cops_style.adoc @@ -8653,6 +8653,10 @@ foo && foo.nil? # method that `nil` responds to foo && foo < bar foo < bar if foo +# When checking `foo&.empty?` in a conditional, `foo` being `nil` will actually +# do the opposite of what the author intends. +foo && foo.empty? + # This could start returning `nil` as well as the return of the method foo.nil? || foo.bar !foo || foo.bar diff --git a/lib/rubocop/cop/style/safe_navigation.rb b/lib/rubocop/cop/style/safe_navigation.rb index 6e2be6f0d55..99e44feab5c 100644 --- a/lib/rubocop/cop/style/safe_navigation.rb +++ b/lib/rubocop/cop/style/safe_navigation.rb @@ -49,6 +49,10 @@ module Style # foo && foo < bar # foo < bar if foo # + # # When checking `foo&.empty?` in a conditional, `foo` being `nil` will actually + # # do the opposite of what the author intends. + # foo && foo.empty? + # # # This could start returning `nil` as well as the return of the method # foo.nil? || foo.bar # !foo || foo.bar @@ -104,6 +108,7 @@ def check_node(node) # chain greater than 2 return if chain_size(method_chain, method) > 1 return if unsafe_method_used?(method_chain, method) + return if method_chain.method?(:empty?) add_offense(node) do |corrector| autocorrect(corrector, node) diff --git a/spec/rubocop/cli/cli_autocorrect_spec.rb b/spec/rubocop/cli/cli_autocorrect_spec.rb index 257b26cdd45..a429b30ef1f 100644 --- a/spec/rubocop/cli/cli_autocorrect_spec.rb +++ b/spec/rubocop/cli/cli_autocorrect_spec.rb @@ -1581,6 +1581,24 @@ def self.some_method(foo, bar: 1) RUBY end + it 'does not crash Lint/SafeNavigationWithEmpty and offenses and accepts Style/SafeNavigation ' \ + 'when checking `foo&.empty?` in a conditional' do + create_file('example.rb', <<~RUBY) + do_something if ENV['VERSION'] && ENV['VERSION'].empty? + RUBY + expect( + cli.run( + [ + '--auto-correct', + '--only', 'Lint/SafeNavigationWithEmpty,Style/SafeNavigation' + ] + ) + ).to eq(0) + expect(IO.read('example.rb')).to eq(<<~RUBY) + do_something if ENV['VERSION'] && ENV['VERSION'].empty? + RUBY + end + it 'corrects TrailingCommaIn(Array|Hash)Literal and ' \ 'Multiline(Array|Hash)BraceLayout offenses' do create_file('.rubocop.yml', <<~YAML) diff --git a/spec/rubocop/cop/style/safe_navigation_spec.rb b/spec/rubocop/cop/style/safe_navigation_spec.rb index a0a0e436b4f..e3a6fa8dd2d 100644 --- a/spec/rubocop/cop/style/safe_navigation_spec.rb +++ b/spec/rubocop/cop/style/safe_navigation_spec.rb @@ -90,6 +90,10 @@ expect_no_offenses('foo && foo.bar !~ /baz/') end + it 'allows an object check before a method call that is used with `empty?`' do + expect_no_offenses('foo && foo.empty?') + end + it 'allows an object check before a method call that is used in ' \ 'a spaceship comparison' do expect_no_offenses('foo && foo.bar <=> baz')