Skip to content

Commit

Permalink
Add new Lint/DuplicateRescueException cop
Browse files Browse the repository at this point in the history
  • Loading branch information
fatkodima committed Jul 23, 2020
1 parent 70ebd34 commit 86a865a
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,7 @@
### New features

* [#8322](https://github.com/rubocop-hq/rubocop/pull/8322): Support autocorrect for `Style/CaseEquality` cop. ([@fatkodima][])
* [#8389](https://github.com/rubocop-hq/rubocop/pull/8389): Add new `Lint/DuplicateRescueException` cop. ([@fatkodima][])
* [#8376](https://github.com/rubocop-hq/rubocop/pull/8376): Add new `Lint/MissingSuper` cop. ([@fatkodima][])
* [#8339](https://github.com/rubocop-hq/rubocop/pull/8339): Add `Config#for_badge` as an efficient way to get a cop's config merged with its department's. ([@marcandre][])
* [#5067](https://github.com/rubocop-hq/rubocop/issues/5067): Add new `Style/StringConcatenation` cop. ([@fatkodima][])
Expand Down
5 changes: 5 additions & 0 deletions config/default.yml
Expand Up @@ -1420,6 +1420,11 @@ Lint/DuplicateMethods:
Enabled: true
VersionAdded: '0.29'

Lint/DuplicateRescueException:
Description: 'Checks that there are no repeated exceptions used in `rescue` expressions.'
Enabled: pending
VersionAdded: '0.89'

Lint/EachWithObjectArgument:
Description: 'Check for immutable argument given to each_with_object.'
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/cops.adoc
Expand Up @@ -196,6 +196,7 @@ In the following section you find all available cops:
* xref:cops_lint.adoc#lintduplicateelsifcondition[Lint/DuplicateElsifCondition]
* xref:cops_lint.adoc#lintduplicatehashkey[Lint/DuplicateHashKey]
* xref:cops_lint.adoc#lintduplicatemethods[Lint/DuplicateMethods]
* 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#lintemptyensure[Lint/EmptyEnsure]
Expand Down
38 changes: 38 additions & 0 deletions docs/modules/ROOT/pages/cops_lint.adoc
Expand Up @@ -739,6 +739,44 @@ end
alias bar foo
----

== Lint/DuplicateRescueException

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

| Pending
| Yes
| No
| 0.89
| -
|===

This cop checks that there are no repeated exceptions
used in 'rescue' expressions.

=== Examples

[source,ruby]
----
# bad
begin
something
rescue FirstException
handle_exception
rescue FirstException
handle_other_exception
end
# good
begin
something
rescue FirstException
handle_exception
rescue SecondException
handle_other_exception
end
----

== Lint/EachWithObjectArgument

|===
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Expand Up @@ -253,6 +253,7 @@
require_relative 'rubocop/cop/lint/duplicate_elsif_condition'
require_relative 'rubocop/cop/lint/duplicate_hash_key'
require_relative 'rubocop/cop/lint/duplicate_methods'
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_ensure'
Expand Down
60 changes: 60 additions & 0 deletions lib/rubocop/cop/lint/duplicate_rescue_exception.rb
@@ -0,0 +1,60 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Lint
# This cop checks that there are no repeated exceptions
# used in 'rescue' expressions.
#
# @example
# # bad
# begin
# something
# rescue FirstException
# handle_exception
# rescue FirstException
# handle_other_exception
# end
#
# # good
# begin
# something
# rescue FirstException
# handle_exception
# rescue SecondException
# handle_other_exception
# end
#
class DuplicateRescueException < Base
include RescueNode

MSG = 'Duplicate `rescue` exception detected.'

def on_rescue(node)
return if rescue_modifier?(node)

_body, *resbodies, _else = *node

resbodies.each_with_object(Set.new) do |resbody, previous|
rescued_exceptions = rescued_exceptions(resbody)

rescued_exceptions.each do |exception|
add_offense(exception) unless previous.add?(exception)
end
end
end

private

def rescued_exceptions(resbody)
rescue_group, = *resbody
if rescue_group
rescue_group.values
else
[]
end
end
end
end
end
end
75 changes: 75 additions & 0 deletions spec/rubocop/cop/lint/duplicate_rescue_exception_spec.rb
@@ -0,0 +1,75 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Lint::DuplicateRescueException do
subject(:cop) { described_class.new }

it 'registers an offense when duplicate exception exists' do
expect_offense(<<~RUBY)
begin
something
rescue FirstError
rescue SecondError, FirstError
^^^^^^^^^^ Duplicate `rescue` exception detected.
end
RUBY
end

it 'registers an offense when duplicate exception splat exists' do
expect_offense(<<~RUBY)
begin
something
rescue *ERRORS
rescue SecondError, *ERRORS
^^^^^^^ Duplicate `rescue` exception detected.
end
RUBY
end

it 'registers an offense when multiple duplicate exceptions exist' do
expect_offense(<<~RUBY)
begin
something
rescue FirstError
rescue SecondError
rescue FirstError
^^^^^^^^^^ Duplicate `rescue` exception detected.
rescue SecondError
^^^^^^^^^^^ Duplicate `rescue` exception detected.
end
RUBY
end

it 'registers an offense when duplicate exception exists within rescues with `else` branch' do
expect_offense(<<~RUBY)
begin
something
rescue FirstError
rescue SecondError, FirstError
^^^^^^^^^^ Duplicate `rescue` exception detected.
else
end
RUBY
end

it 'registers an offense when duplicate exception exists within rescues with empty `rescue` branch' do
expect_offense(<<~RUBY)
begin
something
rescue FirstError
rescue SecondError, FirstError
^^^^^^^^^^ Duplicate `rescue` exception detected.
rescue
end
RUBY
end

it 'does not register an offense when there are no duplicate exceptions' do
expect_no_offenses(<<~RUBY)
begin
something
rescue FirstError
rescue SecondError
end
RUBY
end
end

0 comments on commit 86a865a

Please sign in to comment.