Skip to content

Commit

Permalink
Add new Lint/ConstantOverwrittenInRescue cop
Browse files Browse the repository at this point in the history
This PR is add a new cop.
Checks for overwriting an exception with an exception result by use `rescue =>`.

You intended to write as `rescue StandardError`.
However, you have written `rescue => StandardError`.
In that case, the result of `rescue` will overwrite `StandardError`.

## @example

```ruby
# bad
begin
  something
rescue => StandardError
end

# good
begin
  something
rescue StandardError
end
```
  • Loading branch information
ydah authored and bbatsov committed Jun 20, 2022
1 parent 736e8d6 commit 3b12e71
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 0 deletions.
@@ -0,0 +1 @@
* [#10722](https://github.com/rubocop/rubocop/pull/10722): Add new `Lint/ConstantOverwrittenInRescue` cop. ([@ydah][])
5 changes: 5 additions & 0 deletions config/default.yml
Expand Up @@ -1561,6 +1561,11 @@ Lint/ConstantDefinitionInBlock:
AllowedMethods:
- enums

Lint/ConstantOverwrittenInRescue:
Description: 'Checks for overwriting an exception with an exception result by use `rescue =>`.'
Enabled: pending
VersionAdded: '<<next>>'

Lint/ConstantResolution:
Description: 'Check that constants are fully qualified with `::`.'
Enabled: false
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Expand Up @@ -279,6 +279,7 @@
require_relative 'rubocop/cop/lint/boolean_symbol'
require_relative 'rubocop/cop/lint/circular_argument_reference'
require_relative 'rubocop/cop/lint/constant_definition_in_block'
require_relative 'rubocop/cop/lint/constant_overwritten_in_rescue'
require_relative 'rubocop/cop/lint/constant_resolution'
require_relative 'rubocop/cop/lint/debugger'
require_relative 'rubocop/cop/lint/deprecated_class_methods'
Expand Down
51 changes: 51 additions & 0 deletions lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb
@@ -0,0 +1,51 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Lint
# Checks for overwriting an exception with an exception result by use `rescue =>`.
#
# You intended to write as `rescue StandardError`.
# However, you have written `rescue => StandardError`.
# In that case, the result of `rescue` will overwrite `StandardError`.
#
# @example
#
# # bad
# begin
# something
# rescue => StandardError
# end
#
# # good
# begin
# something
# rescue StandardError
# end
#
class ConstantOverwrittenInRescue < Base
extend AutoCorrector
include RangeHelp

MSG = '`%<constant>s` is overwritten by `rescue =>`.'

# @!method overwritten_constant(node)
def_node_matcher :overwritten_constant, <<~PATTERN
(resbody nil? (casgn nil? $_) nil?)
PATTERN

def self.autocorrect_incompatible_with
[Naming::RescuedExceptionsVariableName, Style::RescueStandardError]
end

def on_resbody(node)
return unless (constant = overwritten_constant(node))

add_offense(node.loc.assoc, message: format(MSG, constant: constant)) do |corrector|
corrector.remove(range_between(node.loc.keyword.end_pos, node.loc.assoc.end_pos))
end
end
end
end
end
end
26 changes: 26 additions & 0 deletions spec/rubocop/cli/autocorrect_spec.rb
Expand Up @@ -2518,4 +2518,30 @@ module Foo#{trailing_whitespace}
end
RUBY
end

it 'corrects `Naming/RescuedExceptionsVariableName` and `, `Style/RescueStandardError`' \
'and `Lint/OverwriteByRescue` offenses' do
source_file = Pathname('example.rb')
create_file(source_file, <<~RUBY)
begin
something
rescue => StandardError
end
RUBY

status = cli.run(
%w[--autocorrect-all --only] << %w[
Naming/RescuedExceptionsVariableName
Style/RescueStandardError
Lint/ConstantOverwrittenInRescue
].join(',')
)
expect(status).to eq(0)
expect(source_file.read).to eq(<<~RUBY)
begin
something
rescue StandardError
end
RUBY
end
end
38 changes: 38 additions & 0 deletions spec/rubocop/cop/lint/constant_overwritten_in_rescue_spec.rb
@@ -0,0 +1,38 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Lint::ConstantOverwrittenInRescue, :config do
it 'registers an offense when overriding an exception with an exception result' do
expect_offense(<<~RUBY)
begin
something
rescue => StandardError
^^ `StandardError` is overwritten by `rescue =>`.
end
RUBY

expect_correction(<<~RUBY)
begin
something
rescue StandardError
end
RUBY
end

it 'does not register an offense when not overriding an exception with an exception result' do
expect_no_offenses(<<~RUBY)
begin
something
rescue StandardError
end
RUBY
end

it 'does not register an offense when using `=>` but correctly assigning to variables' do
expect_no_offenses(<<~RUBY)
begin
something
rescue StandardError => e
end
RUBY
end
end

0 comments on commit 3b12e71

Please sign in to comment.