Skip to content

Commit

Permalink
Add new Lint/EmptyBlock cop
Browse files Browse the repository at this point in the history
  • Loading branch information
fatkodima authored and bbatsov committed Oct 22, 2020
1 parent cb9912f commit 437216b
Show file tree
Hide file tree
Showing 9 changed files with 184 additions and 2 deletions.
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.
# 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|
# # 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

0 comments on commit 437216b

Please sign in to comment.