diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c0eaecec2a..475ea286711 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ * [#7425](https://github.com/rubocop-hq/rubocop/pull/7425): Add new `Lint/TopLevelReturnWithArgument` cop. ([@iamravitejag][]) * [#8417](https://github.com/rubocop-hq/rubocop/pull/8417): Add new `Style/GlobalStdStream` cop. ([@fatkodima][]) * [#7949](https://github.com/rubocop-hq/rubocop/issues/7949): Add new `Style/SingleArgumentDig` cop. ([@volfgox][]) +* [#8341](https://github.com/rubocop-hq/rubocop/pull/8341): Add new `Lint/EmptyConditionalBody` cop. ([@fatkodima][]) ### Bug fixes diff --git a/config/default.yml b/config/default.yml index 17b73c5d7c5..d12af9e9150 100644 --- a/config/default.yml +++ b/config/default.yml @@ -1442,6 +1442,12 @@ Lint/ElseLayout: Enabled: true VersionAdded: '0.17' +Lint/EmptyConditionalBody: + Description: 'This cop checks for the presence of `if`, `elsif` and `unless` branches without a body.' + Enabled: 'pending' + AllowComments: true + VersionAdded: '0.89' + Lint/EmptyEnsure: Description: 'Checks for empty ensure block.' Enabled: true diff --git a/docs/modules/ROOT/pages/cops.adoc b/docs/modules/ROOT/pages/cops.adoc index d35658724c0..b971767730f 100644 --- a/docs/modules/ROOT/pages/cops.adoc +++ b/docs/modules/ROOT/pages/cops.adoc @@ -200,6 +200,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#lintemptyconditionalbody[Lint/EmptyConditionalBody] * xref:cops_lint.adoc#lintemptyensure[Lint/EmptyEnsure] * xref:cops_lint.adoc#lintemptyexpression[Lint/EmptyExpression] * xref:cops_lint.adoc#lintemptyinterpolation[Lint/EmptyInterpolation] diff --git a/docs/modules/ROOT/pages/cops_lint.adoc b/docs/modules/ROOT/pages/cops_lint.adoc index 8ae0fa273cb..440dfe09301 100644 --- a/docs/modules/ROOT/pages/cops_lint.adoc +++ b/docs/modules/ROOT/pages/cops_lint.adoc @@ -893,6 +893,90 @@ else end ---- +== Lint/EmptyConditionalBody + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.89 +| - +|=== + +This cop checks for the presence of `if`, `elsif` and `unless` branches without a body. + +=== Examples + +[source,ruby] +---- +# bad +if condition +end + +# bad +unless condition +end + +# bad +if condition + do_something +elsif other_condition +end + +# good +if condition + do_something +end + +# good +unless condition + do_something +end + +# good +if condition + do_something +elsif other_condition + do_something_else +end +---- + +==== AllowComments: true (default) + +[source,ruby] +---- +# good +if condition + do_something +elsif other_condition + # noop +end +---- + +==== AllowComments: false + +[source,ruby] +---- +# bad +if condition + do_something +elsif other_condition + # noop +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowComments +| `true` +| Boolean +|=== + == Lint/EmptyEnsure |=== diff --git a/lib/rubocop.rb b/lib/rubocop.rb index e7fc39acc2d..aee3e7f71b1 100644 --- a/lib/rubocop.rb +++ b/lib/rubocop.rb @@ -258,6 +258,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_conditional_body' require_relative 'rubocop/cop/lint/empty_ensure' require_relative 'rubocop/cop/lint/empty_expression' require_relative 'rubocop/cop/lint/empty_interpolation' diff --git a/lib/rubocop/cop/lint/empty_conditional_body.rb b/lib/rubocop/cop/lint/empty_conditional_body.rb new file mode 100644 index 00000000000..2938bbc46b0 --- /dev/null +++ b/lib/rubocop/cop/lint/empty_conditional_body.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Lint + # This cop checks for the presence of `if`, `elsif` and `unless` branches without a body. + # @example + # # bad + # if condition + # end + # + # # bad + # unless condition + # end + # + # # bad + # if condition + # do_something + # elsif other_condition + # end + # + # # good + # if condition + # do_something + # end + # + # # good + # unless condition + # do_something + # end + # + # # good + # if condition + # do_something + # elsif other_condition + # do_something_else + # end + # + # @example AllowComments: true (default) + # # good + # if condition + # do_something + # elsif other_condition + # # noop + # end + # + # @example AllowComments: false + # # bad + # if condition + # do_something + # elsif other_condition + # # noop + # end + # + class EmptyConditionalBody < Base + MSG = 'Avoid `%s` branches without a body.' + + def on_if(node) + return if node.body + return if cop_config['AllowComments'] && comment_lines?(node) + + add_offense(node, message: format(MSG, keyword: node.keyword)) + end + end + end + end +end diff --git a/spec/rubocop/cop/lint/empty_conditional_body_spec.rb b/spec/rubocop/cop/lint/empty_conditional_body_spec.rb new file mode 100644 index 00000000000..fd21b0426df --- /dev/null +++ b/spec/rubocop/cop/lint/empty_conditional_body_spec.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::Lint::EmptyConditionalBody, :config do + let(:cop_config) do + { 'AllowComments' => true } + end + + it 'registers an offense for missing `if` body' do + expect_offense(<<~RUBY) + if condition + ^^^^^^^^^^^^ Avoid `if` branches without a body. + end + RUBY + end + + it 'does not register an offense for missing `if` body with a comment' do + expect_no_offenses(<<~RUBY) + if condition + # noop + end + RUBY + end + + it 'registers an offense for missing `elsif` body' do + expect_offense(<<~RUBY) + if condition + do_something + elsif other_condition + ^^^^^^^^^^^^^^^^^^^^^ Avoid `elsif` branches without a body. + end + RUBY + end + + it 'does not register an offense for missing `elsif` body with a comment' do + expect_no_offenses(<<~RUBY) + if condition + do_something + elsif other_condition + # noop + end + RUBY + end + + it 'registers an offense for missing `unless` body' do + expect_offense(<<~RUBY) + unless condition + ^^^^^^^^^^^^^^^^ Avoid `unless` branches without a body. + end + RUBY + end + + it 'does not register an offense for missing `unless` body with a comment' do + expect_no_offenses(<<~RUBY) + unless condition + # noop + end + RUBY + end + + context 'when AllowComments is false' do + let(:cop_config) do + { 'AllowComments' => false } + end + + it 'registers an offense for missing `if` body with a comment' do + expect_offense(<<~RUBY) + if condition + ^^^^^^^^^^^^ Avoid `if` branches without a body. + # noop + end + RUBY + end + + it 'registers an offense for missing `elsif` body with a comment' do + expect_offense(<<~RUBY) + if condition + do_something + elsif other_condition + ^^^^^^^^^^^^^^^^^^^^^ Avoid `elsif` branches without a body. + # noop + end + RUBY + end + + it 'registers an offense for missing `unless` body with a comment' do + expect_offense(<<~RUBY) + unless condition + ^^^^^^^^^^^^^^^^ Avoid `unless` branches without a body. + # noop + end + RUBY + end + end +end