Skip to content

Commit 873cb9f

Browse files
ydahbbatsov
authored andcommitted
Fix an incorrect autocorrect for Style/RedundantException when message is not string
1 parent e162c99 commit 873cb9f

File tree

3 files changed

+113
-26
lines changed

3 files changed

+113
-26
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#12177](https://github.com/rubocop/rubocop/pull/12177): Fix an incorrect autocorrect for `Style/RedundantException`. ([@ydah][])

lib/rubocop/cop/style/redundant_exception.rb

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,21 @@ module Cop
55
module Style
66
# Checks for RuntimeError as the argument of raise/fail.
77
#
8-
# It checks for code like this:
9-
#
108
# @example
11-
# # Bad
9+
# # bad
1210
# raise RuntimeError, 'message'
13-
#
14-
# # Bad
1511
# raise RuntimeError.new('message')
1612
#
17-
# # Good
13+
# # good
1814
# raise 'message'
15+
#
16+
# # bad - message is not a string
17+
# raise RuntimeError, Object.new
18+
# raise RuntimeError.new(Object.new)
19+
#
20+
# # good
21+
# raise Object.new.to_s
22+
#
1923
class RedundantException < Base
2024
extend AutoCorrector
2125

@@ -30,26 +34,42 @@ def on_send(node)
3034
fix_exploded(node) || fix_compact(node)
3135
end
3236

37+
private
38+
3339
def fix_exploded(node)
3440
exploded?(node) do |command, message|
3541
add_offense(node, message: MSG_1) do |corrector|
36-
if node.parenthesized?
37-
corrector.replace(node, "#{command}(#{message.source})")
38-
else
39-
corrector.replace(node, "#{command} #{message.source}")
40-
end
42+
corrector.replace(node, replaced_exploded(node, command, message))
4143
end
4244
end
4345
end
4446

47+
def replaced_exploded(node, command, message)
48+
arg = string_message?(message) ? message.source : "#{message.source}.to_s"
49+
arg = node.parenthesized? ? "(#{arg})" : " #{arg}"
50+
"#{command}#{arg}"
51+
end
52+
53+
def string_message?(message)
54+
message.str_type? || message.dstr_type? || message.xstr_type?
55+
end
56+
4557
def fix_compact(node)
4658
compact?(node) do |new_call, message|
4759
add_offense(node, message: MSG_2) do |corrector|
48-
corrector.replace(new_call, message.source)
60+
corrector.replace(new_call, replaced_compact(message))
4961
end
5062
end
5163
end
5264

65+
def replaced_compact(message)
66+
if string_message?(message)
67+
message.source
68+
else
69+
"#{message.source}.to_s"
70+
end
71+
end
72+
5373
# @!method exploded?(node)
5474
def_node_matcher :exploded?, <<~PATTERN
5575
(send nil? ${:raise :fail} (const {nil? cbase} :RuntimeError) $_)

spec/rubocop/cop/style/redundant_exception_spec.rb

Lines changed: 80 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,59 +4,125 @@
44
shared_examples 'common behavior' do |keyword, runtime_error|
55
it "reports an offense for a #{keyword} with #{runtime_error}" do
66
expect_offense(<<~RUBY, keyword: keyword, runtime_error: runtime_error)
7-
%{keyword} %{runtime_error}, msg
8-
^{keyword}^^{runtime_error}^^^^^ Redundant `RuntimeError` argument can be removed.
7+
%{keyword} %{runtime_error}, "message"
8+
^{keyword}^^{runtime_error}^^^^^^^^^^^ Redundant `RuntimeError` argument can be removed.
99
RUBY
1010

1111
expect_correction(<<~RUBY)
12-
#{keyword} msg
12+
#{keyword} "message"
1313
RUBY
1414
end
1515

1616
it "reports an offense for a #{keyword} with #{runtime_error} and ()" do
1717
expect_offense(<<~RUBY, keyword: keyword, runtime_error: runtime_error)
18-
%{keyword}(%{runtime_error}, msg)
19-
^{keyword}^^{runtime_error}^^^^^^ Redundant `RuntimeError` argument can be removed.
18+
%{keyword}(%{runtime_error}, "message")
19+
^{keyword}^^{runtime_error}^^^^^^^^^^^^ Redundant `RuntimeError` argument can be removed.
2020
RUBY
2121

2222
expect_correction(<<~RUBY)
23-
#{keyword}(msg)
23+
#{keyword}("message")
2424
RUBY
2525
end
2626

2727
it "reports an offense for a #{keyword} with #{runtime_error}.new" do
2828
expect_offense(<<~RUBY, keyword: keyword, runtime_error: runtime_error)
29-
%{keyword} %{runtime_error}.new msg
30-
^{keyword}^^{runtime_error}^^^^^^^^ Redundant `RuntimeError.new` call can be replaced with just the message.
29+
%{keyword} %{runtime_error}.new "message"
30+
^{keyword}^^{runtime_error}^^^^^^^^^^^^^^ Redundant `RuntimeError.new` call can be replaced with just the message.
3131
RUBY
3232

3333
expect_correction(<<~RUBY)
34-
#{keyword} msg
34+
#{keyword} "message"
3535
RUBY
3636
end
3737

3838
it "reports an offense for a #{keyword} with #{runtime_error}.new" do
3939
expect_offense(<<~RUBY, keyword: keyword, runtime_error: runtime_error)
40-
%{keyword} %{runtime_error}.new(msg)
41-
^{keyword}^^{runtime_error}^^^^^^^^^ Redundant `RuntimeError.new` call can be replaced with just the message.
40+
%{keyword} %{runtime_error}.new("message")
41+
^{keyword}^^{runtime_error}^^^^^^^^^^^^^^^ Redundant `RuntimeError.new` call can be replaced with just the message.
4242
RUBY
4343

4444
expect_correction(<<~RUBY)
45-
#{keyword} msg
45+
#{keyword} "message"
4646
RUBY
4747
end
4848

4949
it "accepts a #{keyword} with #{runtime_error} if it does not have 2 args" do
50-
expect_no_offenses("#{keyword} #{runtime_error}, msg, caller")
50+
expect_no_offenses("#{keyword} #{runtime_error}, 'message', caller")
5151
end
5252

5353
it 'accepts rescue w/ non redundant error' do
54-
expect_no_offenses "#{keyword} OtherError, msg"
54+
expect_no_offenses "#{keyword} OtherError, 'message'"
5555
end
5656
end
5757

5858
include_examples 'common behavior', 'raise', 'RuntimeError'
5959
include_examples 'common behavior', 'raise', '::RuntimeError'
6060
include_examples 'common behavior', 'fail', 'RuntimeError'
6161
include_examples 'common behavior', 'fail', '::RuntimeError'
62+
63+
it 'registers an offense for raise with RuntimeError, "#{message}"' do
64+
expect_offense(<<~'RUBY')
65+
raise RuntimeError, "#{message}"
66+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Redundant `RuntimeError` argument can be removed.
67+
RUBY
68+
69+
expect_correction(<<~'RUBY')
70+
raise "#{message}"
71+
RUBY
72+
end
73+
74+
it 'registers an offense for raise with RuntimeError, `command`' do
75+
expect_offense(<<~RUBY)
76+
raise RuntimeError, `command`
77+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Redundant `RuntimeError` argument can be removed.
78+
RUBY
79+
80+
expect_correction(<<~RUBY)
81+
raise `command`
82+
RUBY
83+
end
84+
85+
it 'registers an offense for raise with RuntimeError, Object.new' do
86+
expect_offense(<<~RUBY)
87+
raise RuntimeError, Object.new
88+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Redundant `RuntimeError` argument can be removed.
89+
RUBY
90+
91+
expect_correction(<<~RUBY)
92+
raise Object.new.to_s
93+
RUBY
94+
end
95+
96+
it 'registers an offense for raise with RuntimeError.new, Object.new and parans' do
97+
expect_offense(<<~RUBY)
98+
raise RuntimeError.new(Object.new)
99+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Redundant `RuntimeError.new` call can be replaced with just the message.
100+
RUBY
101+
102+
expect_correction(<<~RUBY)
103+
raise Object.new.to_s
104+
RUBY
105+
end
106+
107+
it 'registers an offense for raise with RuntimeError.new, Object.new no parens' do
108+
expect_offense(<<~RUBY)
109+
raise RuntimeError.new Object.new
110+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Redundant `RuntimeError.new` call can be replaced with just the message.
111+
RUBY
112+
113+
expect_correction(<<~RUBY)
114+
raise Object.new.to_s
115+
RUBY
116+
end
117+
118+
it 'registers an offense for raise with RuntimeError, valiable' do
119+
expect_offense(<<~RUBY)
120+
raise RuntimeError, valiable
121+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Redundant `RuntimeError` argument can be removed.
122+
RUBY
123+
124+
expect_correction(<<~RUBY)
125+
raise valiable.to_s
126+
RUBY
127+
end
62128
end

0 commit comments

Comments
 (0)