From 631120b803ddf096922832d41ea88afd212e5ed0 Mon Sep 17 00:00:00 2001 From: linshuy2 Date: Sat, 31 Jan 2026 17:48:26 +0000 Subject: [PATCH] fix: `unwrap_used` and `expect_used` FN when using fully qualified syntax --- clippy_lints/src/methods/mod.rs | 10 +++ .../src/methods/unwrap_expect_used.rs | 68 +++++++++++++++++++ tests/ui/unwrap_expect_used.rs | 12 ++++ tests/ui/unwrap_expect_used.stderr | 50 +++++++++++++- 4 files changed, 139 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs index 3ca7f6bc29c5..355b34d195da 100644 --- a/clippy_lints/src/methods/mod.rs +++ b/clippy_lints/src/methods/mod.rs @@ -4965,6 +4965,16 @@ impl<'tcx> LateLintPass<'tcx> for Methods { io_other_error::check(cx, expr, func, args, self.msrv); swap_with_temporary::check(cx, expr, func, args); ip_constant::check(cx, expr, func, args); + unwrap_expect_used::check_call( + cx, + expr, + func, + args, + self.allow_unwrap_in_tests, + self.allow_expect_in_tests, + self.allow_unwrap_in_consts, + self.allow_expect_in_consts, + ); }, ExprKind::MethodCall(..) => { self.check_methods(cx, expr); diff --git a/clippy_lints/src/methods/unwrap_expect_used.rs b/clippy_lints/src/methods/unwrap_expect_used.rs index 30db2a75df57..4effab3a5e63 100644 --- a/clippy_lints/src/methods/unwrap_expect_used.rs +++ b/clippy_lints/src/methods/unwrap_expect_used.rs @@ -3,6 +3,7 @@ use clippy_utils::res::MaybeDef; use clippy_utils::ty::is_never_like; use clippy_utils::{is_in_test, is_inside_always_const_context, is_lint_allowed}; use rustc_hir::Expr; +use rustc_hir::def::DefKind; use rustc_lint::{LateContext, Lint}; use rustc_middle::ty; use rustc_span::sym; @@ -87,3 +88,70 @@ pub(super) fn check( }, ); } + +#[expect(clippy::too_many_arguments, clippy::fn_params_excessive_bools)] +pub(super) fn check_call( + cx: &LateContext<'_>, + expr: &Expr<'_>, + func: &Expr<'_>, + args: &[Expr<'_>], + allow_unwrap_in_consts: bool, + allow_unwrap_in_tests: bool, + allow_expect_in_consts: bool, + allow_expect_in_tests: bool, +) { + let Some(recv) = args.first() else { + return; + }; + let Some((DefKind::AssocFn, def_id)) = cx.typeck_results().type_dependent_def(func.hir_id) else { + return; + }; + + match cx.tcx.item_name(def_id) { + sym::unwrap => { + check( + cx, + expr, + recv, + false, + allow_unwrap_in_consts, + allow_unwrap_in_tests, + Variant::Unwrap, + ); + }, + sym::expect => { + check( + cx, + expr, + recv, + false, + allow_expect_in_consts, + allow_expect_in_tests, + Variant::Expect, + ); + }, + clippy_utils::sym::unwrap_err => { + check( + cx, + expr, + recv, + true, + allow_unwrap_in_consts, + allow_unwrap_in_tests, + Variant::Unwrap, + ); + }, + clippy_utils::sym::expect_err => { + check( + cx, + expr, + recv, + true, + allow_expect_in_consts, + allow_expect_in_tests, + Variant::Expect, + ); + }, + _ => (), + } +} diff --git a/tests/ui/unwrap_expect_used.rs b/tests/ui/unwrap_expect_used.rs index b429f3a8a0bb..207d4dd815be 100644 --- a/tests/ui/unwrap_expect_used.rs +++ b/tests/ui/unwrap_expect_used.rs @@ -83,3 +83,15 @@ mod with_expansion { let _ = open!(file).expect_err("can open"); //~ expect_used } } + +fn issue16484() { + let opt = Some(()); + Option::unwrap(opt); //~ unwrap_used + Option::expect(opt, "error message"); //~ expect_used + + let res: Result<(), i32> = Ok(()); + Result::unwrap(res); //~ unwrap_used + Result::expect(res, "error message"); //~ expect_used + Result::unwrap_err(res); //~ unwrap_used + Result::expect_err(res, "error message"); //~ expect_used +} diff --git a/tests/ui/unwrap_expect_used.stderr b/tests/ui/unwrap_expect_used.stderr index 6fd1b84d8123..b9a2844b284c 100644 --- a/tests/ui/unwrap_expect_used.stderr +++ b/tests/ui/unwrap_expect_used.stderr @@ -82,5 +82,53 @@ LL | let _ = open!(file).expect_err("can open"); | = note: if this value is an `Ok`, it will panic -error: aborting due to 10 previous errors +error: used `unwrap()` on an `Option` value + --> tests/ui/unwrap_expect_used.rs:89:5 + | +LL | Option::unwrap(opt); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is `None`, it will panic + +error: used `expect()` on an `Option` value + --> tests/ui/unwrap_expect_used.rs:90:5 + | +LL | Option::expect(opt, "error message"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is `None`, it will panic + +error: used `unwrap()` on a `Result` value + --> tests/ui/unwrap_expect_used.rs:93:5 + | +LL | Result::unwrap(res); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is an `Err`, it will panic + +error: used `expect()` on a `Result` value + --> tests/ui/unwrap_expect_used.rs:94:5 + | +LL | Result::expect(res, "error message"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is an `Err`, it will panic + +error: used `unwrap_err()` on a `Result` value + --> tests/ui/unwrap_expect_used.rs:95:5 + | +LL | Result::unwrap_err(res); + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is an `Ok`, it will panic + +error: used `expect_err()` on a `Result` value + --> tests/ui/unwrap_expect_used.rs:96:5 + | +LL | Result::expect_err(res, "error message"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: if this value is an `Ok`, it will panic + +error: aborting due to 16 previous errors