summary refs log tree commit diff
diff options
context:
space:
mode:
authoryanglsh <yanglsh@shanghaitech.edu.cn>2025-03-14 00:15:02 +0800
committeryanglsh <yanglsh@shanghaitech.edu.cn>2025-03-14 13:51:08 +0800
commit80ce9d1effd19b42a3eea3c571634960ab9a90ef (patch)
treeb65ae6fef70354cd2a8ea98e63ca001f74d9ff30
parent18061e2c42c719d0d483b9bebdc853ec189ba121 (diff)
downloadrust-80ce9d1effd19b42a3eea3c571634960ab9a90ef.tar.gz
rust-80ce9d1effd19b42a3eea3c571634960ab9a90ef.zip
fix: `borrow_deref_ref` suggests wrongly when coerce to mut
-rw-r--r--clippy_lints/src/borrow_deref_ref.rs5
-rw-r--r--tests/ui/borrow_deref_ref.fixed43
-rw-r--r--tests/ui/borrow_deref_ref.rs43
-rw-r--r--tests/ui/borrow_deref_ref.stderr8
4 files changed, 97 insertions, 2 deletions
diff --git a/clippy_lints/src/borrow_deref_ref.rs b/clippy_lints/src/borrow_deref_ref.rs
index 8892a9e6b6b..cfe5e424ff7 100644
--- a/clippy_lints/src/borrow_deref_ref.rs
+++ b/clippy_lints/src/borrow_deref_ref.rs
@@ -2,7 +2,7 @@ use crate::reference::DEREF_ADDROF;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed};
+use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed, is_mutable};
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
@@ -73,6 +73,9 @@ impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
                 }
             })
             && !is_from_proc_macro(cx, e)
+            && let e_ty = cx.typeck_results().expr_ty_adjusted(e)
+            // check if the reference is coercing to a mutable reference
+            && (!matches!(e_ty.kind(), ty::Ref(_, _, Mutability::Mut)) || is_mutable(cx, deref_target))
             && let Some(deref_text) = deref_target.span.get_source_text(cx)
         {
             span_lint_and_then(
diff --git a/tests/ui/borrow_deref_ref.fixed b/tests/ui/borrow_deref_ref.fixed
index 17c224f10bf..765dd75fceb 100644
--- a/tests/ui/borrow_deref_ref.fixed
+++ b/tests/ui/borrow_deref_ref.fixed
@@ -81,3 +81,46 @@ fn issue_13584() {
     let p = &raw const *s;
     let _ = p as *const i8;
 }
+
+mod issue_9905 {
+    use std::{fs, io};
+
+    pub enum File {
+        Stdio,
+        File(fs::File),
+    }
+
+    impl io::Read for &'_ File {
+        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+            match self {
+                File::Stdio => io::stdin().read(buf),
+                File::File(file) => (&*file).read(buf),
+            }
+        }
+    }
+}
+
+mod issue_11346 {
+    struct Struct;
+
+    impl Struct {
+        fn foo(self: &mut &Self) {}
+    }
+
+    trait Trait {
+        fn bar(&mut self) {}
+    }
+
+    impl Trait for &Struct {}
+
+    fn bar() {
+        let s = &Struct;
+        (&*s).foo();
+        (&*s).bar();
+
+        let mut s = &Struct;
+        s.foo(); // To avoid a warning about `s` not needing to be mutable
+        s.foo();
+        //~^ borrow_deref_ref
+    }
+}
diff --git a/tests/ui/borrow_deref_ref.rs b/tests/ui/borrow_deref_ref.rs
index 130ed2903dc..8ee66bfa881 100644
--- a/tests/ui/borrow_deref_ref.rs
+++ b/tests/ui/borrow_deref_ref.rs
@@ -81,3 +81,46 @@ fn issue_13584() {
     let p = &raw const *s;
     let _ = p as *const i8;
 }
+
+mod issue_9905 {
+    use std::{fs, io};
+
+    pub enum File {
+        Stdio,
+        File(fs::File),
+    }
+
+    impl io::Read for &'_ File {
+        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+            match self {
+                File::Stdio => io::stdin().read(buf),
+                File::File(file) => (&*file).read(buf),
+            }
+        }
+    }
+}
+
+mod issue_11346 {
+    struct Struct;
+
+    impl Struct {
+        fn foo(self: &mut &Self) {}
+    }
+
+    trait Trait {
+        fn bar(&mut self) {}
+    }
+
+    impl Trait for &Struct {}
+
+    fn bar() {
+        let s = &Struct;
+        (&*s).foo();
+        (&*s).bar();
+
+        let mut s = &Struct;
+        s.foo(); // To avoid a warning about `s` not needing to be mutable
+        (&*s).foo();
+        //~^ borrow_deref_ref
+    }
+}
diff --git a/tests/ui/borrow_deref_ref.stderr b/tests/ui/borrow_deref_ref.stderr
index f5868aa8749..3d55da25b9b 100644
--- a/tests/ui/borrow_deref_ref.stderr
+++ b/tests/ui/borrow_deref_ref.stderr
@@ -19,5 +19,11 @@ error: deref on an immutable reference
 LL |         let addr_y = &&*x as *const _ as usize; // assert ok
    |                       ^^^ help: if you would like to reborrow, try removing `&*`: `x`
 
-error: aborting due to 3 previous errors
+error: deref on an immutable reference
+  --> tests/ui/borrow_deref_ref.rs:123:9
+   |
+LL |         (&*s).foo();
+   |         ^^^^^ help: if you would like to reborrow, try removing `&*`: `s`
+
+error: aborting due to 4 previous errors