Skip to content

Commit 849c1c0

Browse files
committed
Auto merge of rust-lang#9338 - sgued:9331-unwrap-err-used, r=giraffate
unwrap_used and expect_used: trigger on uses of their _err variants changelog: [`unwrap_used`]: lint uses of `unwrap_err` changelog: [`expect_used`]: lint uses of `expect_err` fixes rust-lang#9331
2 parents 84fb7e0 + ab91d5a commit 849c1c0

File tree

9 files changed

+101
-24
lines changed

9 files changed

+101
-24
lines changed

clippy_lints/src/methods/expect_used.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,26 @@ use rustc_span::sym;
77

88
use super::EXPECT_USED;
99

10-
/// lint use of `expect()` for `Option`s and `Result`s
11-
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_expect_in_tests: bool) {
10+
/// lint use of `expect()` or `expect_err` for `Result` and `expect()` for `Option`.
11+
pub(super) fn check(
12+
cx: &LateContext<'_>,
13+
expr: &hir::Expr<'_>,
14+
recv: &hir::Expr<'_>,
15+
is_err: bool,
16+
allow_expect_in_tests: bool,
17+
) {
1218
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
1319

14-
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
20+
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
1521
Some((EXPECT_USED, "an Option", "None", ""))
1622
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
17-
Some((EXPECT_USED, "a Result", "Err", "an "))
23+
Some((EXPECT_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
1824
} else {
1925
None
2026
};
2127

28+
let method = if is_err { "expect_err" } else { "expect" };
29+
2230
if allow_expect_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
2331
return;
2432
}
@@ -28,7 +36,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
2836
cx,
2937
lint,
3038
expr.span,
31-
&format!("used `expect()` on `{kind}` value"),
39+
&format!("used `{method}()` on `{kind}` value"),
3240
None,
3341
&format!("if this value is {none_prefix}`{none_value}`, it will panic"),
3442
);

clippy_lints/src/methods/mod.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ declare_clippy_lint! {
174174

175175
declare_clippy_lint! {
176176
/// ### What it does
177-
/// Checks for `.unwrap()` calls on `Option`s and on `Result`s.
177+
/// Checks for `.unwrap()` or `.unwrap_err()` calls on `Result`s and `.unwrap()` call on `Option`s.
178178
///
179179
/// ### Why is this bad?
180180
/// It is better to handle the `None` or `Err` case,
@@ -224,7 +224,7 @@ declare_clippy_lint! {
224224

225225
declare_clippy_lint! {
226226
/// ### What it does
227-
/// Checks for `.expect()` calls on `Option`s and `Result`s.
227+
/// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s.
228228
///
229229
/// ### Why is this bad?
230230
/// Usually it is better to handle the `None` or `Err` case.
@@ -2740,8 +2740,9 @@ impl Methods {
27402740
("expect", [_]) => match method_call(recv) {
27412741
Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
27422742
Some(("err", [recv], err_span)) => err_expect::check(cx, expr, recv, self.msrv, span, err_span),
2743-
_ => expect_used::check(cx, expr, recv, self.allow_expect_in_tests),
2743+
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
27442744
},
2745+
("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
27452746
("extend", [arg]) => {
27462747
string_extend_chars::check(cx, expr, recv, arg);
27472748
extend_with_drain::check(cx, expr, recv, arg);
@@ -2874,8 +2875,9 @@ impl Methods {
28742875
},
28752876
_ => {},
28762877
}
2877-
unwrap_used::check(cx, expr, recv, self.allow_unwrap_in_tests);
2878+
unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
28782879
},
2880+
("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
28792881
("unwrap_or", [u_arg]) => match method_call(recv) {
28802882
Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
28812883
manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);

clippy_lints/src/methods/unwrap_used.rs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,26 @@ use rustc_span::sym;
77

88
use super::{EXPECT_USED, UNWRAP_USED};
99

10-
/// lint use of `unwrap()` for `Option`s and `Result`s
11-
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) {
10+
/// lint use of `unwrap()` or `unwrap_err` for `Result` and `unwrap()` for `Option`.
11+
pub(super) fn check(
12+
cx: &LateContext<'_>,
13+
expr: &hir::Expr<'_>,
14+
recv: &hir::Expr<'_>,
15+
is_err: bool,
16+
allow_unwrap_in_tests: bool,
17+
) {
1218
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
1319

14-
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
20+
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) && !is_err {
1521
Some((UNWRAP_USED, "an Option", "None", ""))
1622
} else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
17-
Some((UNWRAP_USED, "a Result", "Err", "an "))
23+
Some((UNWRAP_USED, "a Result", if is_err { "Ok" } else { "Err" }, "an "))
1824
} else {
1925
None
2026
};
2127

28+
let method_suffix = if is_err { "_err" } else { "" };
29+
2230
if allow_unwrap_in_tests && is_in_test_function(cx.tcx, expr.hir_id) {
2331
return;
2432
}
@@ -27,7 +35,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
2735
let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
2836
format!(
2937
"if you don't want to handle the `{none_value}` case gracefully, consider \
30-
using `expect()` to provide a better panic message"
38+
using `expect{method_suffix}()` to provide a better panic message"
3139
)
3240
} else {
3341
format!("if this value is {none_prefix}`{none_value}`, it will panic")
@@ -37,7 +45,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
3745
cx,
3846
lint,
3947
expr.span,
40-
&format!("used `unwrap()` on `{kind}` value"),
48+
&format!("used `unwrap{method_suffix}()` on `{kind}` value"),
4149
None,
4250
&help,
4351
);

tests/ui/expect.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ fn expect_option() {
66
}
77

88
fn expect_result() {
9-
let res: Result<u8, ()> = Ok(0);
9+
let res: Result<u8, u8> = Ok(0);
1010
let _ = res.expect("");
11+
let _ = res.expect_err("");
1112
}
1213

1314
fn main() {

tests/ui/expect.stderr

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,13 @@ LL | let _ = res.expect("");
1515
|
1616
= help: if this value is an `Err`, it will panic
1717

18-
error: aborting due to 2 previous errors
18+
error: used `expect_err()` on `a Result` value
19+
--> $DIR/expect.rs:11:13
20+
|
21+
LL | let _ = res.expect_err("");
22+
| ^^^^^^^^^^^^^^^^^^
23+
|
24+
= help: if this value is an `Ok`, it will panic
25+
26+
error: aborting due to 3 previous errors
1927

tests/ui/unwrap.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ fn unwrap_option() {
66
}
77

88
fn unwrap_result() {
9-
let res: Result<u8, ()> = Ok(0);
9+
let res: Result<u8, u8> = Ok(0);
1010
let _ = res.unwrap();
11+
let _ = res.unwrap_err();
1112
}
1213

1314
fn main() {

tests/ui/unwrap.stderr

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,13 @@ LL | let _ = res.unwrap();
1515
|
1616
= help: if you don't want to handle the `Err` case gracefully, consider using `expect()` to provide a better panic message
1717

18-
error: aborting due to 2 previous errors
18+
error: used `unwrap_err()` on `a Result` value
19+
--> $DIR/unwrap.rs:11:13
20+
|
21+
LL | let _ = res.unwrap_err();
22+
| ^^^^^^^^^^^^^^^^
23+
|
24+
= help: if you don't want to handle the `Ok` case gracefully, consider using `expect_err()` to provide a better panic message
25+
26+
error: aborting due to 3 previous errors
1927

tests/ui/unwrap_expect_used.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,35 @@
11
#![warn(clippy::unwrap_used, clippy::expect_used)]
22

3+
trait OptionExt {
4+
type Item;
5+
6+
fn unwrap_err(self) -> Self::Item;
7+
8+
fn expect_err(self, msg: &str) -> Self::Item;
9+
}
10+
11+
impl<T> OptionExt for Option<T> {
12+
type Item = T;
13+
fn unwrap_err(self) -> T {
14+
panic!();
15+
}
16+
17+
fn expect_err(self, msg: &str) -> T {
18+
panic!();
19+
}
20+
}
21+
322
fn main() {
423
Some(3).unwrap();
524
Some(3).expect("Hello world!");
625

26+
// Don't trigger on unwrap_err on an option
27+
Some(3).unwrap_err();
28+
Some(3).expect_err("Hellow none!");
29+
730
let a: Result<i32, i32> = Ok(3);
831
a.unwrap();
932
a.expect("Hello world!");
33+
a.unwrap_err();
34+
a.expect_err("Hello error!");
1035
}

tests/ui/unwrap_expect_used.stderr

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: used `unwrap()` on `an Option` value
2-
--> $DIR/unwrap_expect_used.rs:4:5
2+
--> $DIR/unwrap_expect_used.rs:23:5
33
|
44
LL | Some(3).unwrap();
55
| ^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | Some(3).unwrap();
88
= help: if this value is `None`, it will panic
99

1010
error: used `expect()` on `an Option` value
11-
--> $DIR/unwrap_expect_used.rs:5:5
11+
--> $DIR/unwrap_expect_used.rs:24:5
1212
|
1313
LL | Some(3).expect("Hello world!");
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,20 +17,36 @@ LL | Some(3).expect("Hello world!");
1717
= help: if this value is `None`, it will panic
1818

1919
error: used `unwrap()` on `a Result` value
20-
--> $DIR/unwrap_expect_used.rs:8:5
20+
--> $DIR/unwrap_expect_used.rs:31:5
2121
|
2222
LL | a.unwrap();
2323
| ^^^^^^^^^^
2424
|
2525
= help: if this value is an `Err`, it will panic
2626

2727
error: used `expect()` on `a Result` value
28-
--> $DIR/unwrap_expect_used.rs:9:5
28+
--> $DIR/unwrap_expect_used.rs:32:5
2929
|
3030
LL | a.expect("Hello world!");
3131
| ^^^^^^^^^^^^^^^^^^^^^^^^
3232
|
3333
= help: if this value is an `Err`, it will panic
3434

35-
error: aborting due to 4 previous errors
35+
error: used `unwrap_err()` on `a Result` value
36+
--> $DIR/unwrap_expect_used.rs:33:5
37+
|
38+
LL | a.unwrap_err();
39+
| ^^^^^^^^^^^^^^
40+
|
41+
= help: if this value is an `Ok`, it will panic
42+
43+
error: used `expect_err()` on `a Result` value
44+
--> $DIR/unwrap_expect_used.rs:34:5
45+
|
46+
LL | a.expect_err("Hello error!");
47+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
48+
|
49+
= help: if this value is an `Ok`, it will panic
50+
51+
error: aborting due to 6 previous errors
3652

0 commit comments

Comments
 (0)