Skip to content

Commit 6b697db

Browse files
committed
fix(clone_on_ref_ptr): only name the generic type if possible
1 parent 99b8106 commit 6b697db

File tree

4 files changed

+84
-8
lines changed

4 files changed

+84
-8
lines changed

clippy_lints/src/methods/clone_on_ref_ptr.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use clippy_utils::source::snippet_with_context;
33
use rustc_errors::Applicability;
44
use rustc_hir as hir;
55
use rustc_lint::LateContext;
6-
use rustc_middle::ty;
6+
use rustc_middle::ty::{self, IsSuggestable};
77
use rustc_span::symbol::sym;
88

99
use super::CLONE_ON_REF_PTR;
@@ -30,12 +30,22 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, receiver: &hir::
3030
// Sometimes unnecessary ::<_> after Rc/Arc/Weak
3131
let mut app = Applicability::Unspecified;
3232
let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0;
33-
diag.span_suggestion(
34-
expr.span,
35-
"try",
36-
format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)),
37-
app,
38-
);
33+
let generic = subst.type_at(0);
34+
if generic.is_suggestable(cx.tcx, true) {
35+
diag.span_suggestion(
36+
expr.span,
37+
"try",
38+
format!("{caller_type}::<{generic}>::clone(&{snippet})"),
39+
app,
40+
);
41+
} else {
42+
diag.span_suggestion(
43+
expr.span,
44+
"try",
45+
format!("{caller_type}::</* generic */>::clone(&{snippet})"),
46+
Applicability::HasPlaceholders,
47+
);
48+
}
3949
},
4050
);
4151
}

tests/ui/clone_on_ref_ptr.fixed

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,33 @@ mod issue2076 {
4949
//~^ clone_on_ref_ptr
5050
}
5151
}
52+
53+
#[allow(
54+
clippy::needless_borrow,
55+
reason = "the suggestion creates `Weak::clone(&rec)`, but `rec` is already a reference"
56+
)]
57+
mod issue15009 {
58+
use std::rc::{Rc, Weak};
59+
use std::sync::atomic::{AtomicU32, Ordering};
60+
61+
fn main() {
62+
let counter = AtomicU32::new(0);
63+
let counter_ref = &counter;
64+
let factorial = Rc::new_cyclic(move |rec| {
65+
let rec = std::rc::Weak::</* generic */>::clone(&rec) as Weak<dyn Fn(u32) -> u32>;
66+
//~^ clone_on_ref_ptr
67+
move |x| {
68+
// can capture env
69+
counter_ref.fetch_add(1, Ordering::Relaxed);
70+
match x {
71+
0 => 1,
72+
x => x * rec.upgrade().unwrap()(x - 1),
73+
}
74+
}
75+
});
76+
println!("{}", factorial(5)); // 120
77+
println!("{}", counter.load(Ordering::Relaxed)); // 6
78+
println!("{}", factorial(7)); // 5040
79+
println!("{}", counter.load(Ordering::Relaxed)); // 14
80+
}
81+
}

tests/ui/clone_on_ref_ptr.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,33 @@ mod issue2076 {
4949
//~^ clone_on_ref_ptr
5050
}
5151
}
52+
53+
#[allow(
54+
clippy::needless_borrow,
55+
reason = "the suggestion creates `Weak::clone(&rec)`, but `rec` is already a reference"
56+
)]
57+
mod issue15009 {
58+
use std::rc::{Rc, Weak};
59+
use std::sync::atomic::{AtomicU32, Ordering};
60+
61+
fn main() {
62+
let counter = AtomicU32::new(0);
63+
let counter_ref = &counter;
64+
let factorial = Rc::new_cyclic(move |rec| {
65+
let rec = rec.clone() as Weak<dyn Fn(u32) -> u32>;
66+
//~^ clone_on_ref_ptr
67+
move |x| {
68+
// can capture env
69+
counter_ref.fetch_add(1, Ordering::Relaxed);
70+
match x {
71+
0 => 1,
72+
x => x * rec.upgrade().unwrap()(x - 1),
73+
}
74+
}
75+
});
76+
println!("{}", factorial(5)); // 120
77+
println!("{}", counter.load(Ordering::Relaxed)); // 6
78+
println!("{}", factorial(7)); // 5040
79+
println!("{}", counter.load(Ordering::Relaxed)); // 14
80+
}
81+
}

tests/ui/clone_on_ref_ptr.stderr

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,11 @@ error: using `.clone()` on a ref-counted pointer
3737
LL | Some(try_opt!(Some(rc)).clone())
3838
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::rc::Rc::<u8>::clone(&try_opt!(Some(rc)))`
3939

40-
error: aborting due to 6 previous errors
40+
error: using `.clone()` on a ref-counted pointer
41+
--> tests/ui/clone_on_ref_ptr.rs:65:23
42+
|
43+
LL | let rec = rec.clone() as Weak<dyn Fn(u32) -> u32>;
44+
| ^^^^^^^^^^^ help: try: `std::rc::Weak::</* generic */>::clone(&rec)`
45+
46+
error: aborting due to 7 previous errors
4147

0 commit comments

Comments
 (0)