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/EmptyBlock cop #8895

Merged
merged 1 commit into from Oct 22, 2020
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,10 @@

## master (unreleased)

### New features

* [#8895](https://github.com/rubocop-hq/rubocop/pull/8895): Add new `Lint/EmptyBlock` cop. ([@fatkodima][])

## 1.0.0 (2020-10-21)

### New features
Expand Down
6 changes: 6 additions & 0 deletions config/default.yml
Expand Up @@ -1474,6 +1474,12 @@ Lint/ElseLayout:
Enabled: true
VersionAdded: '0.17'

Lint/EmptyBlock:
Description: 'This cop checks for blocks without a body.'
Enabled: pending
VersionAdded: '1.1'
AllowComments: true

Lint/EmptyConditionalBody:
Description: 'This cop checks for the presence of `if`, `elsif` and `unless` branches without a body.'
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/cops.adoc
Expand Up @@ -204,6 +204,7 @@ In the following section you find all available cops:
* xref:cops_lint.adoc#lintduplicaterescueexception[Lint/DuplicateRescueException]
* xref:cops_lint.adoc#linteachwithobjectargument[Lint/EachWithObjectArgument]
* xref:cops_lint.adoc#lintelselayout[Lint/ElseLayout]
* xref:cops_lint.adoc#lintemptyblock[Lint/EmptyBlock]
* xref:cops_lint.adoc#lintemptyconditionalbody[Lint/EmptyConditionalBody]
* xref:cops_lint.adoc#lintemptyensure[Lint/EmptyEnsure]
* xref:cops_lint.adoc#lintemptyexpression[Lint/EmptyExpression]
Expand Down
61 changes: 61 additions & 0 deletions docs/modules/ROOT/pages/cops_lint.adoc
Expand Up @@ -994,6 +994,67 @@ else
end
----

== Lint/EmptyBlock

|===
| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged

| Pending
| Yes
| No
| 1.1
| -
|===

This cop checks for blocks without a body.
Such empty blocks are typically an oversight or we should provide a comment
be clearer what we're aiming for.

=== Examples

[source,ruby]
----
# bad
items.each { |item| }

# good
items.each { |item| puts item }
----

==== AllowComments: true (default)

[source,ruby]
----
# good
items.each do |item|
# TODO: implement later (inner comment)
end

items.each { |item| } # TODO: implement later (inline comment)
----

==== AllowComments: false

[source,ruby]
----
# bad
items.each do |item|
# TODO: implement later (inner comment)
end

items.each { |item| } # TODO: implement later (inline comment)
----

=== Configurable attributes

|===
| Name | Default value | Configurable values

| AllowComments
| `true`
| Boolean
|===

== Lint/EmptyConditionalBody

|===
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Expand Up @@ -266,6 +266,7 @@
require_relative 'rubocop/cop/lint/duplicate_rescue_exception'
require_relative 'rubocop/cop/lint/each_with_object_argument'
require_relative 'rubocop/cop/lint/else_layout'
require_relative 'rubocop/cop/lint/empty_block'
require_relative 'rubocop/cop/lint/empty_conditional_body'
require_relative 'rubocop/cop/lint/empty_ensure'
require_relative 'rubocop/cop/lint/empty_expression'
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cli/command/auto_genenerate_config.rb
Expand Up @@ -90,7 +90,7 @@ def run_all_cops(line_length_contents)
def reset_config_and_auto_gen_file
@config_store = ConfigStore.new
@config_store.options_config = @options[:config] if @options[:config]
File.open(AUTO_GENERATED_FILE, 'w') {}
File.open(AUTO_GENERATED_FILE, 'w') {} # create or truncate if exists
add_inheritance_from_auto_generated_file(@options[:config])
end

Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/corrector.rb
Expand Up @@ -23,7 +23,7 @@ def initialize(source)
)

# Don't print warnings to stderr if corrections conflict with each other
diagnostics.consumer = ->(diagnostic) {}
diagnostics.consumer = ->(diagnostic) {} # noop
end

alias rewrite process # Legacy
Expand Down
46 changes: 46 additions & 0 deletions lib/rubocop/cop/lint/empty_block.rb
@@ -0,0 +1,46 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Lint
# This cop checks for blocks without a body.
fatkodima marked this conversation as resolved.
Show resolved Hide resolved
# Such empty blocks are typically an oversight or we should provide a comment
# be clearer what we're aiming for.
#
# @example
# # bad
# items.each { |item| }
#
# # good
# items.each { |item| puts item }
#
# @example AllowComments: true (default)
# # good
# items.each do |item|
fatkodima marked this conversation as resolved.
Show resolved Hide resolved
# # TODO: implement later (inner comment)
# end
#
# items.each { |item| } # TODO: implement later (inline comment)
#
# @example AllowComments: false
# # bad
# items.each do |item|
# # TODO: implement later (inner comment)
# end
#
# items.each { |item| } # TODO: implement later (inline comment)
#
class EmptyBlock < Base
MSG = 'Empty block detected.'

def on_block(node)
return if node.body
return if cop_config['AllowComments'] &&
processed_source.contains_comment?(node.source_range)

add_offense(node)
end
end
end
end
end
63 changes: 63 additions & 0 deletions spec/rubocop/cop/lint/empty_block_spec.rb
@@ -0,0 +1,63 @@
# frozen_string_literal: true

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

it 'registers an offense for empty block within method call' do
expect_offense(<<~RUBY)
items.each { |item| }
^^^^^^^^^^^^^^^^^^^^^ Empty block detected.
RUBY
end

it 'registers an offense for empty block within lambda' do
expect_offense(<<~RUBY)
lambda { |item| }
^^^^^^^^^^^^^^^^^ Empty block detected.
RUBY
end

it 'does not register an offense for empty block with inner comments' do
expect_no_offenses(<<~RUBY)
items.each do |item|
# TODO: implement later
end
RUBY
end

it 'does not register an offense for empty block with inline comments' do
expect_no_offenses(<<~RUBY)
items.each { |item| } # TODO: implement later
RUBY
end

it 'does not register an offense when block is not empty' do
expect_no_offenses(<<~RUBY)
items.each { |item| puts item }
RUBY
end

context 'when AllowComments is false' do
let(:cop_config) do
{ 'AllowComments' => false }
end

it 'registers an offense for empty block with inner comments' do
expect_offense(<<~RUBY)
items.each do |item|
^^^^^^^^^^^^^^^^^^^^ Empty block detected.
# TODO: implement later
end
RUBY
end

it 'registers an offense for empty block with inline comments' do
expect_offense(<<~RUBY)
items.each { |item| } # TODO: implement later
^^^^^^^^^^^^^^^^^^^^^ Empty block detected.
RUBY
end
end
end