Skip to content

Commit b890b8d

Browse files
committed
fix(clone_on_ref_ptr): only name the generic type if possible
1 parent d3c4150 commit b890b8d

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::{Symbol, sym};
88

99
use super::CLONE_ON_REF_PTR;
@@ -37,12 +37,22 @@ pub(super) fn check(
3737
// Sometimes unnecessary ::<_> after Rc/Arc/Weak
3838
let mut app = Applicability::Unspecified;
3939
let snippet = snippet_with_context(cx, receiver.span, expr.span.ctxt(), "..", &mut app).0;
40-
diag.span_suggestion(
41-
expr.span,
42-
"try",
43-
format!("{caller_type}::<{}>::clone(&{snippet})", subst.type_at(0)),
44-
app,
45-
);
40+
let generic = subst.type_at(0);
41+
if generic.is_suggestable(cx.tcx, true) {
42+
diag.span_suggestion(
43+
expr.span,
44+
"try",
45+
format!("{caller_type}::<{generic}>::clone(&{snippet})"),
46+
app,
47+
);
48+
} else {
49+
diag.span_suggestion(
50+
expr.span,
51+
"try",
52+
format!("{caller_type}::</* generic */>::clone(&{snippet})"),
53+
Applicability::HasPlaceholders,
54+
);
55+
}
4656
},
4757
);
4858
}

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)