Auto merge of #12615 - Kobzol:fix-recursive-clone-from, r=blyxyas

Do not suggest `assigning_clones` in `Clone` impl

This PR modifies `assigning_clones` to detect situations where the `clone` call is inside a `Clone` impl, and avoids suggesting the lint in such situations.

r? `@blyxyas`

Fixes: https://github.com/rust-lang/rust-clippy/issues/12600

changelog: Do not invoke `assigning_clones` inside `Clone` impl
This commit is contained in:
bors 2024-04-03 19:07:51 +00:00
commit e80ca2f381
4 changed files with 49 additions and 6 deletions

View File

@ -181,6 +181,23 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
return false; return false;
} }
// If the call expression is inside an impl block that contains the method invoked by the
// call expression, we bail out to avoid suggesting something that could result in endless
// recursion.
if let Some(local_block_id) = impl_block.as_local()
&& let Some(block) = cx.tcx.hir_node_by_def_id(local_block_id).as_owner()
{
let impl_block_owner = block.def_id();
if cx
.tcx
.hir()
.parent_id_iter(lhs.hir_id)
.any(|parent| parent.owner == impl_block_owner)
{
return false;
}
}
// Find the function for which we want to check that it is implemented. // Find the function for which we want to check that it is implemented.
let provided_fn = match call.target { let provided_fn = match call.target {
TargetTrait::Clone => cx.tcx.get_diagnostic_item(sym::Clone).and_then(|clone| { TargetTrait::Clone => cx.tcx.get_diagnostic_item(sym::Clone).and_then(|clone| {

View File

@ -153,6 +153,19 @@ fn clone_inside_macro() {
clone_inside!(a, b); clone_inside!(a, b);
} }
// Make sure that we don't suggest the lint when we call clone inside a Clone impl
// https://github.com/rust-lang/rust-clippy/issues/12600
pub struct AvoidRecursiveCloneFrom;
impl Clone for AvoidRecursiveCloneFrom {
fn clone(&self) -> Self {
Self
}
fn clone_from(&mut self, source: &Self) {
*self = source.clone();
}
}
// ToOwned // ToOwned
fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) { fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) {
ref_str.clone_into(mut_string); ref_str.clone_into(mut_string);

View File

@ -153,6 +153,19 @@ fn clone_inside_macro() {
clone_inside!(a, b); clone_inside!(a, b);
} }
// Make sure that we don't suggest the lint when we call clone inside a Clone impl
// https://github.com/rust-lang/rust-clippy/issues/12600
pub struct AvoidRecursiveCloneFrom;
impl Clone for AvoidRecursiveCloneFrom {
fn clone(&self) -> Self {
Self
}
fn clone_from(&mut self, source: &Self) {
*self = source.clone();
}
}
// ToOwned // ToOwned
fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) { fn owned_method_mut_ref(mut_string: &mut String, ref_str: &str) {
*mut_string = ref_str.to_owned(); *mut_string = ref_str.to_owned();

View File

@ -86,37 +86,37 @@ LL | a = c.to_owned();
| ^^^^^^^^^^^^^^^^ help: use `clone_into()`: `c.clone_into(&mut a)` | ^^^^^^^^^^^^^^^^ help: use `clone_into()`: `c.clone_into(&mut a)`
error: assigning the result of `ToOwned::to_owned()` may be inefficient error: assigning the result of `ToOwned::to_owned()` may be inefficient
--> tests/ui/assigning_clones.rs:158:5 --> tests/ui/assigning_clones.rs:171:5
| |
LL | *mut_string = ref_str.to_owned(); LL | *mut_string = ref_str.to_owned();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(mut_string)` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(mut_string)`
error: assigning the result of `ToOwned::to_owned()` may be inefficient error: assigning the result of `ToOwned::to_owned()` may be inefficient
--> tests/ui/assigning_clones.rs:162:5 --> tests/ui/assigning_clones.rs:175:5
| |
LL | mut_string = ref_str.to_owned(); LL | mut_string = ref_str.to_owned();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut mut_string)` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut mut_string)`
error: assigning the result of `ToOwned::to_owned()` may be inefficient error: assigning the result of `ToOwned::to_owned()` may be inefficient
--> tests/ui/assigning_clones.rs:183:5 --> tests/ui/assigning_clones.rs:196:5
| |
LL | **mut_box_string = ref_str.to_owned(); LL | **mut_box_string = ref_str.to_owned();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
error: assigning the result of `ToOwned::to_owned()` may be inefficient error: assigning the result of `ToOwned::to_owned()` may be inefficient
--> tests/ui/assigning_clones.rs:187:5 --> tests/ui/assigning_clones.rs:200:5
| |
LL | **mut_box_string = ref_str.to_owned(); LL | **mut_box_string = ref_str.to_owned();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
error: assigning the result of `ToOwned::to_owned()` may be inefficient error: assigning the result of `ToOwned::to_owned()` may be inefficient
--> tests/ui/assigning_clones.rs:191:5 --> tests/ui/assigning_clones.rs:204:5
| |
LL | *mut_thing = ToOwned::to_owned(ref_str); LL | *mut_thing = ToOwned::to_owned(ref_str);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, mut_thing)` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, mut_thing)`
error: assigning the result of `ToOwned::to_owned()` may be inefficient error: assigning the result of `ToOwned::to_owned()` may be inefficient
--> tests/ui/assigning_clones.rs:195:5 --> tests/ui/assigning_clones.rs:208:5
| |
LL | mut_thing = ToOwned::to_owned(ref_str); LL | mut_thing = ToOwned::to_owned(ref_str);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, &mut mut_thing)` | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, &mut mut_thing)`