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

Add new Lint/EmptyInPattern cop #9825

Merged
merged 1 commit into from May 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/new_add_new_lint_empty_in_pattern_cop.md
@@ -0,0 +1 @@
* [#9825](https://github.com/rubocop/rubocop/pull/9825): Add new `Lint/EmptyInPattern` cop. ([@koic][])
5 changes: 5 additions & 0 deletions config/default.yml
Expand Up @@ -1646,6 +1646,11 @@ Lint/EmptyFile:
AllowComments: true
VersionAdded: '0.90'

Lint/EmptyInPattern:
Description: 'Checks for the presence of `in` pattern branches without a body.'
Enabled: pending
VersionAdded: '<<next>>'

Lint/EmptyInterpolation:
Description: 'Checks for empty string interpolation.'
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Expand Up @@ -288,6 +288,7 @@
require_relative 'rubocop/cop/lint/empty_ensure'
require_relative 'rubocop/cop/lint/empty_expression'
require_relative 'rubocop/cop/lint/empty_file'
require_relative 'rubocop/cop/lint/empty_in_pattern'
require_relative 'rubocop/cop/lint/empty_interpolation'
require_relative 'rubocop/cop/lint/empty_when'
require_relative 'rubocop/cop/lint/ensure_return'
Expand Down
62 changes: 62 additions & 0 deletions lib/rubocop/cop/lint/empty_in_pattern.rb
@@ -0,0 +1,62 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Lint
# This cop checks for the presence of `in` pattern branches without a body.
#
# @example
#
# # bad
# case condition
# in [a]
# do_something
# in [a, b]
# end
#
# # good
# case condition
# in [a]
# do_something
# in [a, b]
# nil
# end
#
# @example AllowComments: true (default)
#
# # good
# case condition
# in [a]
# do_something
# in [a, b]
# # noop
# end
#
# @example AllowComments: false
#
# # bad
# case condition
# in [a]
# do_something
# in [a, b]
# # noop
# end
#
class EmptyInPattern < Base
extend TargetRubyVersion

MSG = 'Avoid `in` branches without a body.'

minimum_target_ruby_version 2.7

def on_case_match(node)
node.in_pattern_branches.each do |branch|
next if branch.body || cop_config['AllowComments'] && comment_lines?(node)

add_offense(branch)
end
end
end
end
end
end
2 changes: 1 addition & 1 deletion rubocop.gemspec
Expand Up @@ -35,7 +35,7 @@ Gem::Specification.new do |s|
s.add_runtime_dependency('rainbow', '>= 2.2.2', '< 4.0')
s.add_runtime_dependency('regexp_parser', '>= 1.8', '< 3.0')
s.add_runtime_dependency('rexml')
s.add_runtime_dependency('rubocop-ast', '>= 1.5.0', '< 2.0')
s.add_runtime_dependency('rubocop-ast', '>= 1.6.0', '< 2.0')
s.add_runtime_dependency('ruby-progressbar', '~> 1.7')
s.add_runtime_dependency('unicode-display_width', '>= 1.4.0', '< 3.0')

Expand Down
165 changes: 165 additions & 0 deletions spec/rubocop/cop/lint/empty_in_pattern_spec.rb
@@ -0,0 +1,165 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Lint::EmptyInPattern, :config do
let(:cop_config) { { 'AllowComments' => false } }

context 'when a `in` body is missing', :ruby27 do
it 'registers an offense for a missing `in` body' do
expect_offense(<<~RUBY)
case foo
in [a] then 1
in [a, b] # nothing
^^^^^^^^^ Avoid `in` branches without a body.
end
RUBY

expect_no_corrections
end

it 'registers an offense for missing `in` body followed by `else`' do
expect_offense(<<~RUBY)
case foo
in [a] then 1
in [a, b] # nothing
^^^^^^^^^ Avoid `in` branches without a body.
else 3
end
RUBY

expect_no_corrections
end

it 'registers an offense for missing `in` ... `then` body' do
expect_offense(<<~RUBY)
case foo
in [a] then 1
in [a, b] then # nothing
^^^^^^^^^ Avoid `in` branches without a body.
end
RUBY

expect_no_corrections
end

it 'registers an offense for missing `in` ... then `body` followed by `else`' do
expect_offense(<<~RUBY)
case foo
in [a] then 1
in [a, b] then # nothing
^^^^^^^^^ Avoid `in` branches without a body.
else 3
end
RUBY

expect_no_corrections
end

it 'registers an offense for missing `in` body with a comment' do
expect_offense(<<~RUBY)
case foo
in [a]
1
in [a, b]
^^^^^^^^^ Avoid `in` branches without a body.
# nothing
end
RUBY

expect_no_corrections
end

it 'registers an offense for missing `in` body with a comment followed by `else`' do
expect_offense(<<~RUBY)
case foo
in [a]
1
in [a, b]
^^^^^^^^^ Avoid `in` branches without a body.
# nothing
else
3
end
RUBY

expect_no_corrections
end
end

context 'when a `in` body is present', :ruby27 do
it 'accepts `case` with `in` ... `then` statements' do
expect_no_offenses(<<~RUBY)
case foo
in [a] then 1
in [a, b] then 2
end
RUBY
end

it 'accepts `case` with `in` ... `then` statements and else clause' do
expect_no_offenses(<<~RUBY)
case foo
in [a] then 1
in [a, b] then 2
else 3
end
RUBY
end

it 'accepts `case` with `in` bodies' do
expect_no_offenses(<<~RUBY)
case foo
in [a]
1
in [a, b]
2
end
RUBY
end

it 'accepts `case` with `in` bodies and `else` clause' do
expect_no_offenses(<<~RUBY)
case foo
in [a]
1
in [a, b]
2
else
3
end
RUBY
end
end

context 'when `AllowComments: true`', :ruby27 do
let(:cop_config) { { 'AllowComments' => true } }

it 'accepts an empty `in` body with a comment' do
expect_no_offenses(<<~RUBY)
case condition
in [a]
do_something
in [a, b]
# do nothing
end
RUBY
end
end

context 'when `AllowComments: false`', :ruby27 do
let(:cop_config) { { 'AllowComments' => false } }

it 'registers an offense for empty `in` body with a comment' do
expect_offense(<<~RUBY)
case condition
in [a]
do_something
in [a, b]
^^^^^^^^^ Avoid `in` branches without a body.
# do nothing
end
RUBY

expect_no_corrections
end
end
end