diff --git a/clippy_lints/src/manual_option_as_slice.rs b/clippy_lints/src/manual_option_as_slice.rs index c4a3ac96b1f8..919b1b2f488c 100644 --- a/clippy_lints/src/manual_option_as_slice.rs +++ b/clippy_lints/src/manual_option_as_slice.rs @@ -5,8 +5,8 @@ use clippy_utils::res::{MaybeDef as _, MaybeQPath as _, MaybeResPath as _}; use clippy_utils::source::snippet_with_context; use clippy_utils::{as_some_pattern, is_none_pattern, msrvs, peel_hir_expr_refs, sym}; use rustc_errors::Applicability; -use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind, QPath, is_range_literal}; -use rustc_lint::{LateContext, LateLintPass, impl_lint_pass}; +use rustc_hir::{Arm, ByRef, Expr, ExprKind, Pat, PatKind, QPath, is_range_literal}; +use rustc_lint::{LateContext, LateLintPass, LintContext as _, impl_lint_pass}; use rustc_span::{Span, Symbol}; declare_clippy_lint! { @@ -66,9 +66,9 @@ impl LateLintPass<'_> for ManualOptionAsSlice { }, ExprKind::If(cond, then, Some(other)) => { if let ExprKind::Let(let_expr) = cond.kind + && is_empty_slice(cx, other.peel_blocks()) && let Some(binding) = extract_ident_from_some_pat(cx, let_expr.pat) && check_some_body(cx, binding, then) - && is_empty_slice(cx, other.peel_blocks()) { check_as_ref(cx, let_expr.init, span, self.msrv); } @@ -142,7 +142,13 @@ fn check_as_ref(cx: &LateContext<'_>, expr: &Expr<'_>, span: Span, msrv: Msrv) { fn extract_ident_from_some_pat(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option { if let Some([binding]) = as_some_pattern(cx, pat) - && let PatKind::Binding(_mode, _hir_id, ident, _inner_pat) = binding.kind + && let PatKind::Binding(_, hir_id, ident, _inner_pat) = binding.kind + && matches!( + cx.typeck_results() + .extract_binding_mode(cx.sess(), hir_id, binding.span) + .0, + ByRef::No + ) { Some(ident.name) } else { diff --git a/tests/ui/manual_option_as_slice.fixed b/tests/ui/manual_option_as_slice.fixed index 5a182630a5ce..063dfd6889d4 100644 --- a/tests/ui/manual_option_as_slice.fixed +++ b/tests/ui/manual_option_as_slice.fixed @@ -49,6 +49,15 @@ fn check(x: Option) { _ = x.as_ref().map_or(&[42][..], std::slice::from_ref); _ = x.as_ref().map_or_else(|| &[42][..1], std::slice::from_ref); _ = x.as_ref().map(|f| std::slice::from_ref(f)).unwrap_or_default(); + + let _: &[&u32] = match x.as_ref() { + Some(ref f) => std::slice::from_ref(f), + None => &[], + }; + let _: &[&u32] = match x.as_ref() { + Some(ref mut f) => std::slice::from_ref(f), + None => &[], + }; } #[clippy::msrv = "1.74"] diff --git a/tests/ui/manual_option_as_slice.rs b/tests/ui/manual_option_as_slice.rs index a29f8d5cddb3..9d7b40f1b27c 100644 --- a/tests/ui/manual_option_as_slice.rs +++ b/tests/ui/manual_option_as_slice.rs @@ -59,6 +59,15 @@ fn check(x: Option) { _ = x.as_ref().map_or(&[42][..], std::slice::from_ref); _ = x.as_ref().map_or_else(|| &[42][..1], std::slice::from_ref); _ = x.as_ref().map(|f| std::slice::from_ref(f)).unwrap_or_default(); + + let _: &[&u32] = match x.as_ref() { + Some(ref f) => std::slice::from_ref(f), + None => &[], + }; + let _: &[&u32] = match x.as_ref() { + Some(ref mut f) => std::slice::from_ref(f), + None => &[], + }; } #[clippy::msrv = "1.74"] diff --git a/tests/ui/manual_option_as_slice_2021.rs b/tests/ui/manual_option_as_slice_2021.rs new file mode 100644 index 000000000000..a9cce3428ea8 --- /dev/null +++ b/tests/ui/manual_option_as_slice_2021.rs @@ -0,0 +1,20 @@ +//@ edition: 2021 +//@ check-pass + +#![warn(clippy::manual_option_as_slice)] + +fn check(x: Option) { + // Edition 2024 drops the `as_ref` temporary before the result of the `if let` is consumed. + _ = if let Some(ref f) = x.as_ref() { + std::slice::from_ref(f) + } else { + &[] + }; + _ = if let Some(ref mut f) = x.as_ref() { + std::slice::from_ref(f) + } else { + &[] + }; +} + +fn main() {}