From 3ddaabcbc9cf223f6a2f8f645b2092166f911eab Mon Sep 17 00:00:00 2001 From: ThibsG Date: Sun, 21 Mar 2021 09:50:35 +0100 Subject: [PATCH] Fix suggestion with generics for `field_reassign_with_default` lint --- clippy_lints/src/default.rs | 19 +++++++++++++++ tests/ui/field_reassign_with_default.rs | 18 ++++++++++++++ tests/ui/field_reassign_with_default.stderr | 26 ++++++++++++++++++++- 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs index d046e8947922..568a174445c1 100644 --- a/clippy_lints/src/default.rs +++ b/clippy_lints/src/default.rs @@ -104,6 +104,7 @@ impl LateLintPass<'_> for Default { } } + #[allow(clippy::too_many_lines)] fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) { // start from the `let mut _ = _::default();` and look at all the following // statements, see if they re-assign the fields of the binding @@ -197,6 +198,24 @@ impl LateLintPass<'_> for Default { .collect::>() .join(", "); + // give correct suggestion if generics are involved (see #6944) + let binding_type = if_chain! { + if let ty::Adt(adt_def, substs) = binding_type.kind(); + if !substs.is_empty(); + let adt_def_ty_name = cx.tcx.item_name(adt_def.did); + let generic_args = substs.iter().collect::>(); + let tys_str = generic_args + .iter() + .map(ToString::to_string) + .collect::>() + .join(", "); + then { + format!("{}::<{}>", adt_def_ty_name, &tys_str) + } else { + binding_type.to_string() + } + }; + let sugg = if ext_with_default { if field_list.is_empty() { format!("{}::default()", binding_type) diff --git a/tests/ui/field_reassign_with_default.rs b/tests/ui/field_reassign_with_default.rs index 9fc208f5332a..1368c5d79848 100644 --- a/tests/ui/field_reassign_with_default.rs +++ b/tests/ui/field_reassign_with_default.rs @@ -136,6 +136,13 @@ fn main() { // Don't lint in external macros field_reassign_with_default!(); + + // be sure suggestion is correct with generics + let mut a: Wrapper = Default::default(); + a.i = true; + + let mut a: WrapperMulti = Default::default(); + a.i = 42; } mod m { @@ -145,3 +152,14 @@ mod m { b: u64, } } + +#[derive(Default)] +struct Wrapper { + i: T, +} + +#[derive(Default)] +struct WrapperMulti { + i: T, + j: U, +} diff --git a/tests/ui/field_reassign_with_default.stderr b/tests/ui/field_reassign_with_default.stderr index 2f0f28f7bb72..dd7c0360bb1e 100644 --- a/tests/ui/field_reassign_with_default.stderr +++ b/tests/ui/field_reassign_with_default.stderr @@ -83,5 +83,29 @@ note: consider initializing the variable with `C { i: vec![1], ..Default::defaul LL | let mut a: C = C::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 7 previous errors +error: field assignment outside of initializer for an instance created with Default::default() + --> $DIR/field_reassign_with_default.rs:142:5 + | +LL | a.i = true; + | ^^^^^^^^^^^ + | +note: consider initializing the variable with `Wrapper:: { i: true }` and removing relevant reassignments + --> $DIR/field_reassign_with_default.rs:141:5 + | +LL | let mut a: Wrapper = Default::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: field assignment outside of initializer for an instance created with Default::default() + --> $DIR/field_reassign_with_default.rs:145:5 + | +LL | a.i = 42; + | ^^^^^^^^^ + | +note: consider initializing the variable with `WrapperMulti:: { i: 42, ..Default::default() }` and removing relevant reassignments + --> $DIR/field_reassign_with_default.rs:144:5 + | +LL | let mut a: WrapperMulti = Default::default(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors