Skip to content

Commit 5516113

Browse files
committed
Restrict lint to Debug types
This avoids having the lint show upon usage of `.err().expect()` on types that do not implement Debug
1 parent 300e2f1 commit 5516113

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed
Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,44 @@
11
use super::ERR_EXPECT;
22
use clippy_utils::{diagnostics::span_lint_and_help, meets_msrv, msrvs, ty::is_type_diagnostic_item};
3+
use clippy_utils::ty::implements_trait;
34
use rustc_lint::LateContext;
5+
use rustc_middle::ty;
6+
use rustc_middle::ty::Ty;
47
use rustc_semver::RustcVersion;
58
use rustc_span::sym;
69

710
pub(super) fn check(cx: &LateContext<'_>, expr: &rustc_hir::Expr<'_>, recv: &rustc_hir::Expr<'_>, msrv: Option<&RustcVersion>) {
8-
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result) & meets_msrv(msrv, &msrvs::EXPECT_ERR) {
9-
span_lint_and_help(
11+
if_chain! {
12+
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
13+
if meets_msrv(msrv, &msrvs::EXPECT_ERR);
14+
15+
let result_type = cx.typeck_results().expr_ty(recv);
16+
if let Some(error_type) = get_error_type(cx, result_type);
17+
if has_debug_impl(error_type, cx);
18+
19+
then {
20+
span_lint_and_help(
1021
cx,
1122
ERR_EXPECT,
1223
expr.span,
1324
"called `.err().expect()` on a `Result` value",
1425
None,
1526
"`.expect_err()` can be called instead",
1627
);
28+
}
1729
}
1830
}
31+
32+
/// Given a `Result<T, E>` type, return its error type (`E`).
33+
fn get_error_type<'a>(cx: &LateContext<'_>, ty: Ty<'a>) -> Option<Ty<'a>> {
34+
match ty.kind() {
35+
ty::Adt(_, substs) if is_type_diagnostic_item(cx, ty, sym::Result) => substs.types().nth(1),
36+
_ => None,
37+
}
38+
}
39+
40+
fn has_debug_impl<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
41+
cx.tcx
42+
.get_diagnostic_item(sym::Debug)
43+
.map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
44+
}

tests/ui/err_expect.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1+
struct MyTypeNonDebug;
2+
3+
#[derive(Debug)]
4+
struct MyTypeDebug;
5+
16
fn main() {
2-
let x: Result<u32, &str> = Ok(10);
3-
x.err().expect("Testing expect_err");
7+
let test_debug: Result<u32, MyTypeDebug> = Ok(0);
8+
test_debug.err().expect("Testing debug type");
9+
10+
let test_non_debug: Result<u32, MyTypeNonDebug> = Ok(0);
11+
test_non_debug.err().expect("Testing non debug type");
412
}

0 commit comments

Comments
 (0)