Skip to content

Commit 542a228

Browse files
committed
Only apply dereference-removing special case for actual references
1 parent 51a1cf0 commit 542a228

File tree

4 files changed

+241
-29
lines changed

4 files changed

+241
-29
lines changed

clippy_lints/src/assigning_clones.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,9 +225,22 @@ fn build_sugg<'tcx>(
225225
match call_kind {
226226
CallKind::Method => {
227227
let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
228-
// `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
229-
Sugg::hir_with_applicability(cx, ref_expr, "_", app)
228+
// If `ref_expr` is a reference, we can remove the dereference operator (`*`) to make
229+
// the generated code a bit simpler. In other cases, we don't do this special case, to avoid
230+
// having to deal with Deref (https://github.com/rust-lang/rust-clippy/issues/12437).
231+
232+
let ty = cx.typeck_results().expr_ty(ref_expr);
233+
if ty.is_ref() {
234+
// Apply special case, remove `*`
235+
// `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
236+
Sugg::hir_with_applicability(cx, ref_expr, "_", app)
237+
} else {
238+
// Keep the original lhs
239+
// `*lhs = self_expr.clone();` -> `(*lhs).clone_from(self_expr)`
240+
Sugg::hir_with_applicability(cx, lhs, "_", app)
241+
}
230242
} else {
243+
// Keep the original lhs
231244
// `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
232245
Sugg::hir_with_applicability(cx, lhs, "_", app)
233246
}
@@ -247,8 +260,16 @@ fn build_sugg<'tcx>(
247260
},
248261
CallKind::Ufcs => {
249262
let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
250-
// `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)`
251-
Sugg::hir_with_applicability(cx, ref_expr, "_", app)
263+
// See special case of removing `*` in method handling above
264+
let ty = cx.typeck_results().expr_ty(ref_expr);
265+
if ty.is_ref() {
266+
// `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)`
267+
Sugg::hir_with_applicability(cx, ref_expr, "_", app)
268+
} else {
269+
// `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut *lhs, self_expr)`
270+
// mut_addr_deref is used to avoid unnecessary parentheses around `*lhs`
271+
Sugg::hir_with_applicability(cx, ref_expr, "_", app).mut_addr_deref()
272+
}
252273
} else {
253274
// `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)`
254275
Sugg::hir_with_applicability(cx, lhs, "_", app).mut_addr()

tests/ui/assigning_clones.fixed

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![allow(clippy::ptr_arg)] // https://github.com/rust-lang/rust-clippy/issues/10612
44
#![allow(clippy::needless_late_init)]
55
#![allow(clippy::box_collection)]
6+
#![allow(clippy::boxed_local)]
67
#![warn(clippy::assigning_clones)]
78

89
use std::borrow::ToOwned;
@@ -182,6 +183,35 @@ impl Clone for AvoidRecursiveCloneFrom {
182183
}
183184
}
184185

186+
// Deref handling
187+
fn clone_into_deref_method(mut a: DerefWrapper<HasCloneFrom>, b: HasCloneFrom) {
188+
(*a).clone_from(&b);
189+
}
190+
191+
fn clone_into_deref_with_clone_method(mut a: DerefWrapperWithClone<HasCloneFrom>, b: HasCloneFrom) {
192+
(*a).clone_from(&b);
193+
}
194+
195+
fn clone_into_box_method(mut a: Box<HasCloneFrom>, b: HasCloneFrom) {
196+
(*a).clone_from(&b);
197+
}
198+
199+
fn clone_into_self_deref_method(a: &mut DerefWrapperWithClone<HasCloneFrom>, b: DerefWrapperWithClone<HasCloneFrom>) {
200+
a.clone_from(&b);
201+
}
202+
203+
fn clone_into_xxx(a: &mut DerefWrapper<HasCloneFrom>, b: DerefWrapper<HasCloneFrom>) {
204+
(**a).clone_from(&b);
205+
}
206+
207+
fn clone_into_deref_function(mut a: DerefWrapper<HasCloneFrom>, b: HasCloneFrom) {
208+
Clone::clone_from(&mut *a, &b);
209+
}
210+
211+
fn clone_into_box_function(mut a: Box<HasCloneFrom>, b: HasCloneFrom) {
212+
Clone::clone_from(&mut *a, &b);
213+
}
214+
185215
// ToOwned
186216
fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) {
187217
ref_str.clone_into(mut_string);
@@ -328,3 +358,45 @@ mod borrowck_conflicts {
328358
path = path.components().as_path().to_owned();
329359
}
330360
}
361+
362+
struct DerefWrapper<T>(T);
363+
364+
impl<T> Deref for DerefWrapper<T> {
365+
type Target = T;
366+
367+
fn deref(&self) -> &Self::Target {
368+
&self.0
369+
}
370+
}
371+
372+
impl<T> DerefMut for DerefWrapper<T> {
373+
fn deref_mut(&mut self) -> &mut Self::Target {
374+
&mut self.0
375+
}
376+
}
377+
378+
struct DerefWrapperWithClone<T>(T);
379+
380+
impl<T> Deref for DerefWrapperWithClone<T> {
381+
type Target = T;
382+
383+
fn deref(&self) -> &Self::Target {
384+
&self.0
385+
}
386+
}
387+
388+
impl<T> DerefMut for DerefWrapperWithClone<T> {
389+
fn deref_mut(&mut self) -> &mut Self::Target {
390+
&mut self.0
391+
}
392+
}
393+
394+
impl<T: Clone> Clone for DerefWrapperWithClone<T> {
395+
fn clone(&self) -> Self {
396+
Self(self.0.clone())
397+
}
398+
399+
fn clone_from(&mut self, source: &Self) {
400+
*self = Self(source.0.clone());
401+
}
402+
}

tests/ui/assigning_clones.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#![allow(clippy::ptr_arg)] // https://github.com/rust-lang/rust-clippy/issues/10612
44
#![allow(clippy::needless_late_init)]
55
#![allow(clippy::box_collection)]
6+
#![allow(clippy::boxed_local)]
67
#![warn(clippy::assigning_clones)]
78

89
use std::borrow::ToOwned;
@@ -182,6 +183,31 @@ impl Clone for AvoidRecursiveCloneFrom {
182183
}
183184
}
184185

186+
// Deref handling
187+
fn clone_into_deref_method(mut a: DerefWrapper<HasCloneFrom>, b: HasCloneFrom) {
188+
*a = b.clone();
189+
}
190+
191+
fn clone_into_deref_with_clone_method(mut a: DerefWrapperWithClone<HasCloneFrom>, b: HasCloneFrom) {
192+
*a = b.clone();
193+
}
194+
195+
fn clone_into_box_method(mut a: Box<HasCloneFrom>, b: HasCloneFrom) {
196+
*a = b.clone();
197+
}
198+
199+
fn clone_into_self_deref_method(a: &mut DerefWrapperWithClone<HasCloneFrom>, b: DerefWrapperWithClone<HasCloneFrom>) {
200+
*a = b.clone();
201+
}
202+
203+
fn clone_into_deref_function(mut a: DerefWrapper<HasCloneFrom>, b: HasCloneFrom) {
204+
*a = Clone::clone(&b);
205+
}
206+
207+
fn clone_into_box_function(mut a: Box<HasCloneFrom>, b: HasCloneFrom) {
208+
*a = Clone::clone(&b);
209+
}
210+
185211
// ToOwned
186212
fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) {
187213
*mut_string = ref_str.to_owned();
@@ -328,3 +354,45 @@ mod borrowck_conflicts {
328354
path = path.components().as_path().to_owned();
329355
}
330356
}
357+
358+
struct DerefWrapper<T>(T);
359+
360+
impl<T> Deref for DerefWrapper<T> {
361+
type Target = T;
362+
363+
fn deref(&self) -> &Self::Target {
364+
&self.0
365+
}
366+
}
367+
368+
impl<T> DerefMut for DerefWrapper<T> {
369+
fn deref_mut(&mut self) -> &mut Self::Target {
370+
&mut self.0
371+
}
372+
}
373+
374+
struct DerefWrapperWithClone<T>(T);
375+
376+
impl<T> Deref for DerefWrapperWithClone<T> {
377+
type Target = T;
378+
379+
fn deref(&self) -> &Self::Target {
380+
&self.0
381+
}
382+
}
383+
384+
impl<T> DerefMut for DerefWrapperWithClone<T> {
385+
fn deref_mut(&mut self) -> &mut Self::Target {
386+
&mut self.0
387+
}
388+
}
389+
390+
impl<T: Clone> Clone for DerefWrapperWithClone<T> {
391+
fn clone(&self) -> Self {
392+
Self(self.0.clone())
393+
}
394+
395+
fn clone_from(&mut self, source: &Self) {
396+
*self = Self(source.0.clone());
397+
}
398+
}

0 commit comments

Comments
 (0)