Auto merge of #12742 - Alexendoo:assigning-clones-nested-late-init, r=dswij

Don't lint assigning_clones on nested late init locals

Fixes #12741

changelog: none
This commit is contained in:
bors 2024-05-04 19:36:06 +00:00
commit 28002514d5
5 changed files with 39 additions and 14 deletions

View file

@ -2,9 +2,9 @@ use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::HirNode; use clippy_utils::macros::HirNode;
use clippy_utils::sugg::Sugg; use clippy_utils::sugg::Sugg;
use clippy_utils::{is_trait_method, path_to_local}; use clippy_utils::{is_trait_method, local_is_initialized, path_to_local};
use rustc_errors::Applicability; use rustc_errors::Applicability;
use rustc_hir::{self as hir, Expr, ExprKind, Node}; use rustc_hir::{self as hir, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass}; use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Instance, Mutability}; use rustc_middle::ty::{self, Instance, Mutability};
use rustc_session::impl_lint_pass; use rustc_session::impl_lint_pass;
@ -164,9 +164,7 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
// TODO: This check currently bails if the local variable has no initializer. // TODO: This check currently bails if the local variable has no initializer.
// That is overly conservative - the lint should fire even if there was no initializer, // That is overly conservative - the lint should fire even if there was no initializer,
// but the variable has been initialized before `lhs` was evaluated. // but the variable has been initialized before `lhs` was evaluated.
if let Some(Node::LetStmt(local)) = cx.tcx.hir().parent_id_iter(local).next().map(|p| cx.tcx.hir_node(p)) if !local_is_initialized(cx, local) {
&& local.init.is_none()
{
return false; return false;
} }
} }

View file

@ -192,6 +192,21 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
None None
} }
/// Checks if the given local has an initializer or is from something other than a `let` statement
///
/// e.g. returns true for `x` in `fn f(x: usize) { .. }` and `let x = 1;` but false for `let x;`
pub fn local_is_initialized(cx: &LateContext<'_>, local: HirId) -> bool {
for (_, node) in cx.tcx.hir().parent_iter(local) {
match node {
Node::Pat(..) | Node::PatField(..) => {},
Node::LetStmt(let_stmt) => return let_stmt.init.is_some(),
_ => return true,
}
}
false
}
/// Returns `true` if the given `NodeId` is inside a constant context /// Returns `true` if the given `NodeId` is inside a constant context
/// ///
/// # Example /// # Example

View file

@ -86,6 +86,12 @@ fn assign_to_uninit_mut_var(b: HasCloneFrom) {
a = b.clone(); a = b.clone();
} }
fn late_init_let_tuple() {
let (p, q): (String, String);
p = "ghi".to_string();
q = p.clone();
}
#[derive(Clone)] #[derive(Clone)]
pub struct HasDeriveClone; pub struct HasDeriveClone;

View file

@ -86,6 +86,12 @@ fn assign_to_uninit_mut_var(b: HasCloneFrom) {
a = b.clone(); a = b.clone();
} }
fn late_init_let_tuple() {
let (p, q): (String, String);
p = "ghi".to_string();
q = p.clone();
}
#[derive(Clone)] #[derive(Clone)]
pub struct HasDeriveClone; pub struct HasDeriveClone;

View file

@ -68,55 +68,55 @@ LL | a = b.clone();
| ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` | ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
error: assigning the result of `Clone::clone()` may be inefficient error: assigning the result of `Clone::clone()` may be inefficient
--> tests/ui/assigning_clones.rs:133:5 --> tests/ui/assigning_clones.rs:139:5
| |
LL | a = b.clone(); LL | a = b.clone();
| ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` | ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
error: assigning the result of `Clone::clone()` may be inefficient error: assigning the result of `Clone::clone()` may be inefficient
--> tests/ui/assigning_clones.rs:140:5 --> tests/ui/assigning_clones.rs:146:5
| |
LL | a = b.clone(); LL | a = b.clone();
| ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)` | ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
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:141:5 --> tests/ui/assigning_clones.rs:147:5
| |
LL | a = c.to_owned(); 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:171:5 --> tests/ui/assigning_clones.rs:177: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:175:5 --> tests/ui/assigning_clones.rs:181: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:196:5 --> tests/ui/assigning_clones.rs:202: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:200:5 --> tests/ui/assigning_clones.rs:206: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:204:5 --> tests/ui/assigning_clones.rs:210: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:208:5 --> tests/ui/assigning_clones.rs:214: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)`