about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/default.rs19
-rw-r--r--tests/ui/field_reassign_with_default.rs18
-rw-r--r--tests/ui/field_reassign_with_default.stderr26
3 files changed, 62 insertions, 1 deletions
diff --git a/clippy_lints/src/default.rs b/clippy_lints/src/default.rs
index d046e894792..568a174445c 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::<Vec<String>>()
                     .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::<Vec<_>>();
+                    let tys_str = generic_args
+                        .iter()
+                        .map(ToString::to_string)
+                        .collect::<Vec<_>>()
+                        .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 9fc208f5332..1368c5d7984 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<bool> = Default::default();
+    a.i = true;
+
+    let mut a: WrapperMulti<i32, i64> = Default::default();
+    a.i = 42;
 }
 
 mod m {
@@ -145,3 +152,14 @@ mod m {
         b: u64,
     }
 }
+
+#[derive(Default)]
+struct Wrapper<T> {
+    i: T,
+}
+
+#[derive(Default)]
+struct WrapperMulti<T, U> {
+    i: T,
+    j: U,
+}
diff --git a/tests/ui/field_reassign_with_default.stderr b/tests/ui/field_reassign_with_default.stderr
index 2f0f28f7bb7..dd7c0360bb1 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::<bool> { i: true }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:141:5
+   |
+LL |     let mut a: Wrapper<bool> = 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::<i32, i64> { i: 42, ..Default::default() }` and removing relevant reassignments
+  --> $DIR/field_reassign_with_default.rs:144:5
+   |
+LL |     let mut a: WrapperMulti<i32, i64> = Default::default();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors