about summary refs log tree commit diff
diff options
context:
space:
mode:
authorSamuel Tardieu <sam@rfc1149.net>2025-01-28 00:03:00 +0100
committerSamuel Tardieu <sam@rfc1149.net>2025-01-28 00:08:39 +0100
commit16e2196fc2d9aa87d261e6163e6a13bc9d761f60 (patch)
tree8015a3b8fe5641246b4a80a9399dd376f9c32ac8
parent83bde363b633a68a1a94441b685ee5a87c60879c (diff)
downloadrust-16e2196fc2d9aa87d261e6163e6a13bc9d761f60.tar.gz
rust-16e2196fc2d9aa87d261e6163e6a13bc9d761f60.zip
`useless_asref`: no lint if in a closure to change the ref depth
Removing the `.as_ref()` or `.as_mut()` as the top-level expression in a
closure may change the type of the result. In this case, it may be
better not to lint rather than proposing a fix that would not work.
-rw-r--r--clippy_lints/src/methods/useless_asref.rs19
-rw-r--r--tests/ui/useless_asref.fixed5
-rw-r--r--tests/ui/useless_asref.rs5
3 files changed, 23 insertions, 6 deletions
diff --git a/clippy_lints/src/methods/useless_asref.rs b/clippy_lints/src/methods/useless_asref.rs
index 82313257e5c..6d3da42775f 100644
--- a/clippy_lints/src/methods/useless_asref.rs
+++ b/clippy_lints/src/methods/useless_asref.rs
@@ -55,12 +55,19 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, call_name: &str,
         let (base_res_ty, res_depth) = walk_ptrs_ty_depth(res_ty);
         let (base_rcv_ty, rcv_depth) = walk_ptrs_ty_depth(rcv_ty);
         if base_rcv_ty == base_res_ty && rcv_depth >= res_depth {
-            // allow the `as_ref` or `as_mut` if it is followed by another method call
-            if let Some(parent) = get_parent_expr(cx, expr)
-                && let hir::ExprKind::MethodCall(segment, ..) = parent.kind
-                && segment.ident.span != expr.span
-            {
-                return;
+            if let Some(parent) = get_parent_expr(cx, expr) {
+                // allow the `as_ref` or `as_mut` if it is followed by another method call
+                if let hir::ExprKind::MethodCall(segment, ..) = parent.kind
+                    && segment.ident.span != expr.span
+                {
+                    return;
+                }
+
+                // allow the `as_ref` or `as_mut` if they belong to a closure that changes
+                // the number of references
+                if matches!(parent.kind, hir::ExprKind::Closure(..)) && rcv_depth != res_depth {
+                    return;
+                }
             }
 
             let mut applicability = Applicability::MachineApplicable;
diff --git a/tests/ui/useless_asref.fixed b/tests/ui/useless_asref.fixed
index ddbb9255b46..2f179200bb3 100644
--- a/tests/ui/useless_asref.fixed
+++ b/tests/ui/useless_asref.fixed
@@ -198,6 +198,11 @@ fn issue_12528() {
     let _ = opt.as_ref().map(RcWeak::clone);
 }
 
+fn issue_14088() {
+    let s = Some("foo");
+    let _: Option<&str> = s.as_ref().map(|x| x.as_ref());
+}
+
 fn main() {
     not_ok();
     ok();
diff --git a/tests/ui/useless_asref.rs b/tests/ui/useless_asref.rs
index b0405e930a2..9851a0caac4 100644
--- a/tests/ui/useless_asref.rs
+++ b/tests/ui/useless_asref.rs
@@ -198,6 +198,11 @@ fn issue_12528() {
     let _ = opt.as_ref().map(RcWeak::clone);
 }
 
+fn issue_14088() {
+    let s = Some("foo");
+    let _: Option<&str> = s.as_ref().map(|x| x.as_ref());
+}
+
 fn main() {
     not_ok();
     ok();