Skip to content

Commit 7af5ea1

Browse files
committed
Auto merge of rust-lang#11252 - Centri3:rust-lang#11245, r=xFrednet
[`unwrap_used`]: Do not lint unwrapping on `!` or never-like enums Fixes rust-lang#11245 changelog: [`unwrap_used`]: Do not lint unwrapping on `!` or never-like enums changelog: [`expect_used`]: Do not lint unwrapping on `!` or never-like enums
2 parents 78f5e0d + 71c5413 commit 7af5ea1

File tree

12 files changed

+207
-149
lines changed

12 files changed

+207
-149
lines changed

clippy_lints/src/methods/expect_used.rs

-44
This file was deleted.

clippy_lints/src/methods/mod.rs

+33-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ mod collapsible_str_replace;
1717
mod drain_collect;
1818
mod err_expect;
1919
mod expect_fun_call;
20-
mod expect_used;
2120
mod extend_with_drain;
2221
mod filetype_is_file;
2322
mod filter_map;
@@ -105,7 +104,7 @@ mod unnecessary_lazy_eval;
105104
mod unnecessary_literal_unwrap;
106105
mod unnecessary_sort_by;
107106
mod unnecessary_to_owned;
108-
mod unwrap_used;
107+
mod unwrap_expect_used;
109108
mod useless_asref;
110109
mod utils;
111110
mod vec_resize_to_zero;
@@ -3948,13 +3947,27 @@ impl Methods {
39483947
match method_call(recv) {
39493948
Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
39503949
Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
3951-
_ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
3950+
_ => unwrap_expect_used::check(
3951+
cx,
3952+
expr,
3953+
recv,
3954+
false,
3955+
self.allow_expect_in_tests,
3956+
unwrap_expect_used::Variant::Expect,
3957+
),
39523958
}
39533959
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
39543960
},
39553961
("expect_err", [_]) => {
39563962
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
3957-
expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests);
3963+
unwrap_expect_used::check(
3964+
cx,
3965+
expr,
3966+
recv,
3967+
true,
3968+
self.allow_expect_in_tests,
3969+
unwrap_expect_used::Variant::Expect,
3970+
);
39583971
},
39593972
("extend", [arg]) => {
39603973
string_extend_chars::check(cx, expr, recv, arg);
@@ -4180,11 +4193,25 @@ impl Methods {
41804193
_ => {},
41814194
}
41824195
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
4183-
unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
4196+
unwrap_expect_used::check(
4197+
cx,
4198+
expr,
4199+
recv,
4200+
false,
4201+
self.allow_unwrap_in_tests,
4202+
unwrap_expect_used::Variant::Unwrap,
4203+
);
41844204
},
41854205
("unwrap_err", []) => {
41864206
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
4187-
unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests);
4207+
unwrap_expect_used::check(
4208+
cx,
4209+
expr,
4210+
recv,
4211+
true,
4212+
self.allow_unwrap_in_tests,
4213+
unwrap_expect_used::Variant::Unwrap,
4214+
);
41884215
},
41894216
("unwrap_or", [u_arg]) => {
41904217
match method_call(recv) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
use clippy_utils::diagnostics::span_lint_and_then;
2+
use clippy_utils::ty::{is_never_like, is_type_diagnostic_item};
3+
use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
4+
use rustc_hir::Expr;
5+
use rustc_lint::{LateContext, Lint};
6+
use rustc_middle::ty;
7+
use rustc_span::sym;
8+
9+
use super::{EXPECT_USED, UNWRAP_USED};
10+
11+
#[derive(Clone, Copy, Eq, PartialEq)]
12+
pub(super) enum Variant {
13+
Unwrap,
14+
Expect,
15+
}
16+
17+
impl Variant {
18+
fn method_name(self, is_err: bool) -> &'static str {
19+
match (self, is_err) {
20+
(Variant::Unwrap, true) => "unwrap_err",
21+
(Variant::Unwrap, false) => "unwrap",
22+
(Variant::Expect, true) => "expect_err",
23+
(Variant::Expect, false) => "expect",
24+
}
25+
}
26+
27+
fn lint(self) -> &'static Lint {
28+
match self {
29+
Variant::Unwrap => UNWRAP_USED,
30+
Variant::Expect => EXPECT_USED,
31+
}
32+
}
33+
}
34+
35+
/// Lint usage of `unwrap` or `unwrap_err` for `Result` and `unwrap()` for `Option` (and their
36+
/// `expect` counterparts).
37+
pub(super) fn check(
38+
cx: &LateContext<'_>,
39+
expr: &Expr<'_>,
40+
recv: &Expr<'_>,
41+
is_err: bool,
42+
allow_unwrap_in_tests: bool,
43+
variant: Variant,
44+
) {
45+
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
46+
47+
let (kind, none_value, none_prefix) = if is_type_diagnostic_item(cx, ty, sym::Option) && !is_err {
48+
("an `Option`", "None", "")
49+
} else if is_type_diagnostic_item(cx, ty, sym::Result)
50+
&& let ty::Adt(_, substs) = ty.kind()
51+
&& let Some(t_or_e_ty) = substs[usize::from(!is_err)].as_type()
52+
{
53+
if is_never_like(t_or_e_ty) {
54+
return;
55+
}
56+
57+
("a `Result`", if is_err { "Ok" } else { "Err" }, "an ")
58+
} else {
59+
return;
60+
};
61+
62+
let method_suffix = if is_err { "_err" } else { "" };
63+
64+
if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
65+
return;
66+
}
67+
68+
span_lint_and_then(
69+
cx,
70+
variant.lint(),
71+
expr.span,
72+
&format!("used `{}()` on {kind} value", variant.method_name(is_err)),
73+
|diag| {
74+
diag.note(format!("if this value is {none_prefix}`{none_value}`, it will panic"));
75+
76+
if variant == Variant::Unwrap && is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
77+
diag.help(format!(
78+
"consider using `expect{method_suffix}()` to provide a better panic message"
79+
));
80+
}
81+
},
82+
);
83+
}

clippy_lints/src/methods/unwrap_used.rs

-53
This file was deleted.

clippy_utils/src/ty.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,11 @@ fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[Generi
10931093
}
10941094
}
10951095

1096+
/// Returns whether `ty` is never-like; i.e., `!` (never) or an enum with zero variants.
1097+
pub fn is_never_like(ty: Ty<'_>) -> bool {
1098+
ty.is_never() || (ty.is_enum() && ty.ty_adt_def().is_some_and(|def| def.variants().is_empty()))
1099+
}
1100+
10961101
/// Makes the projection type for the named associated type in the given impl or trait impl.
10971102
///
10981103
/// This function is for associated types which are "known" to exist, and as such, will only return

tests/ui-toml/expect_used/expect_used.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ error: used `expect()` on an `Option` value
44
LL | let _ = opt.expect("");
55
| ^^^^^^^^^^^^^^
66
|
7-
= help: if this value is `None`, it will panic
7+
= note: if this value is `None`, it will panic
88
= note: `-D clippy::expect-used` implied by `-D warnings`
99

1010
error: used `expect()` on a `Result` value
@@ -13,7 +13,7 @@ error: used `expect()` on a `Result` value
1313
LL | let _ = res.expect("");
1414
| ^^^^^^^^^^^^^^
1515
|
16-
= help: if this value is an `Err`, it will panic
16+
= note: if this value is an `Err`, it will panic
1717

1818
error: aborting due to 2 previous errors
1919

0 commit comments

Comments
 (0)