From 1a86849543e0841fd676fa4ef5a2e4637b0f60a6 Mon Sep 17 00:00:00 2001 From: Linshu Yang Date: Tue, 18 Nov 2025 20:12:23 +0000 Subject: [PATCH] fix: `useless_asref` suggests wrongly when used in ctor --- clippy_lints/src/methods/useless_asref.rs | 28 ++++++++++++++++-- tests/ui/useless_asref.fixed | 35 +++++++++++++++++++++++ tests/ui/useless_asref.rs | 35 +++++++++++++++++++++++ tests/ui/useless_asref.stderr | 32 ++++++++++++++++++++- 4 files changed, 127 insertions(+), 3 deletions(-) diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs index 972304d79e75..f852080d0f2a 100644 --- a/clippy_lints/src/methods/useless_asref.rs +++ b/clippy_lints/src/methods/useless_asref.rs @@ -4,7 +4,8 @@ use clippy_utils::source::snippet_with_applicability; use clippy_utils::ty::{implements_trait, peel_and_count_ty_refs, should_call_clone_as_function}; use clippy_utils::{get_parent_expr, peel_blocks, strip_pat_refs}; use rustc_errors::Applicability; -use rustc_hir::{self as hir, LangItem}; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::{self as hir, LangItem, Node}; use rustc_lint::LateContext; use rustc_middle::ty::adjustment::Adjust; use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; @@ -69,14 +70,37 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: Symbo } } + // Add `*` derefs if the expr is used in a ctor, because automatic derefs don't apply in that case. + let deref = if rcv_depth > res_depth { + let parent = cx.tcx.parent_hir_node(expr.hir_id); + match parent { + Node::ExprField(_) => "*".repeat(rcv_depth - res_depth), + Node::Expr(parent) + if let hir::ExprKind::Call(func, _) = parent.kind + && let (_, Some(path)) = func.opt_res_path() + && matches!(path.res, Res::Def(DefKind::Ctor(_, _), _) | Res::SelfCtor(_)) => + { + "*".repeat(rcv_depth - res_depth) + }, + _ => String::new(), + } + } else { + String::new() + }; + let mut applicability = Applicability::MachineApplicable; + let suggestion = format!( + "{deref}{}", + snippet_with_applicability(cx, recvr.span, "..", &mut applicability) + ); + span_lint_and_sugg( cx, USELESS_ASREF, expr.span, format!("this call to `{call_name}` does nothing"), "try", - snippet_with_applicability(cx, recvr.span, "..", &mut applicability).to_string(), + suggestion, applicability, ); } diff --git a/tests/ui/useless_asref.fixed b/tests/ui/useless_asref.fixed index 3c3ea5a736d4..54a7c0a8c080 100644 --- a/tests/ui/useless_asref.fixed +++ b/tests/ui/useless_asref.fixed @@ -258,6 +258,41 @@ fn issue_14828() { ().as_ref(); } +fn issue16098(exts: Vec<&str>) { + use std::borrow::Cow; + + let v: Vec> = exts.iter().map(|s| Cow::Borrowed(*s)).collect(); + //~^ useless_asref + + trait Identity { + fn id(self) -> Self + where + Self: Sized, + { + self + } + } + impl Identity for &str {} + + let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.id())).collect(); + //~^ useless_asref + + let v: Vec> = exts + .iter() + .map(|s| Cow::Borrowed(*std::convert::identity(s))) + //~^ useless_asref + .collect(); + + struct Wrapper<'a>(&'a str); + let exts_field: Vec = exts.iter().map(|s| Wrapper(s)).collect(); + let v: Vec> = exts_field.iter().map(|w| Cow::Borrowed(w.0)).collect(); + //~^ useless_asref + + let exts_index: Vec<&[&str]> = exts.iter().map(|s| std::slice::from_ref(s)).collect(); + let v: Vec> = exts_index.iter().map(|arr| Cow::Borrowed(arr[0])).collect(); + //~^ useless_asref +} + fn main() { not_ok(); ok(); diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs index c173dd677152..1b9ce1d46233 100644 --- a/tests/ui/useless_asref.rs +++ b/tests/ui/useless_asref.rs @@ -258,6 +258,41 @@ fn issue_14828() { ().as_ref(); } +fn issue16098(exts: Vec<&str>) { + use std::borrow::Cow; + + let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.as_ref())).collect(); + //~^ useless_asref + + trait Identity { + fn id(self) -> Self + where + Self: Sized, + { + self + } + } + impl Identity for &str {} + + let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.id().as_ref())).collect(); + //~^ useless_asref + + let v: Vec> = exts + .iter() + .map(|s| Cow::Borrowed(std::convert::identity(s).as_ref())) + //~^ useless_asref + .collect(); + + struct Wrapper<'a>(&'a str); + let exts_field: Vec = exts.iter().map(|s| Wrapper(s)).collect(); + let v: Vec> = exts_field.iter().map(|w| Cow::Borrowed(w.0.as_ref())).collect(); + //~^ useless_asref + + let exts_index: Vec<&[&str]> = exts.iter().map(|s| std::slice::from_ref(s)).collect(); + let v: Vec> = exts_index.iter().map(|arr| Cow::Borrowed(arr[0].as_ref())).collect(); + //~^ useless_asref +} + fn main() { not_ok(); ok(); diff --git a/tests/ui/useless_asref.stderr b/tests/ui/useless_asref.stderr index 8255f5d9d2ab..861472b4419e 100644 --- a/tests/ui/useless_asref.stderr +++ b/tests/ui/useless_asref.stderr @@ -112,5 +112,35 @@ error: this call to `as_ref.map(...)` does nothing LL | Some(1).as_ref().map(|&x| x.clone()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(1).clone()` -error: aborting due to 18 previous errors +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:264:66 + | +LL | let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.as_ref())).collect(); + | ^^^^^^^^^^ help: try: `*s` + +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:277:66 + | +LL | let v: Vec> = exts.iter().map(|s| Cow::Borrowed(s.id().as_ref())).collect(); + | ^^^^^^^^^^^^^^^ help: try: `s.id()` + +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:282:32 + | +LL | .map(|s| Cow::Borrowed(std::convert::identity(s).as_ref())) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `*std::convert::identity(s)` + +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:288:72 + | +LL | let v: Vec> = exts_field.iter().map(|w| Cow::Borrowed(w.0.as_ref())).collect(); + | ^^^^^^^^^^^^ help: try: `w.0` + +error: this call to `as_ref` does nothing + --> tests/ui/useless_asref.rs:292:74 + | +LL | let v: Vec> = exts_index.iter().map(|arr| Cow::Borrowed(arr[0].as_ref())).collect(); + | ^^^^^^^^^^^^^^^ help: try: `arr[0]` + +error: aborting due to 23 previous errors