1 // aux-build:proc_macro_derive.rs
2 // aux-build:macro_rules.rs
3 
4 #![warn(clippy::field_reassign_with_default)]
5 
6 #[macro_use]
7 extern crate proc_macro_derive;
8 #[macro_use]
9 extern crate macro_rules;
10 
11 // Don't lint on derives that derive `Default`
12 // See https://github.com/rust-lang/rust-clippy/issues/6545
13 #[derive(FieldReassignWithDefault)]
14 struct DerivedStruct;
15 
16 #[derive(Default)]
17 struct A {
18     i: i32,
19     j: i64,
20 }
21 
22 struct B {
23     i: i32,
24     j: i64,
25 }
26 
27 #[derive(Default)]
28 struct C {
29     i: Vec<i32>,
30     j: i64,
31 }
32 
33 #[derive(Default)]
34 struct D {
35     a: Option<i32>,
36     b: Option<i32>,
37 }
38 
39 macro_rules! m {
40     ($key:ident: $value:tt) => {{
41         let mut data = $crate::D::default();
42         data.$key = Some($value);
43         data
44     }};
45 }
46 
47 /// Implements .next() that returns a different number each time.
48 struct SideEffect(i32);
49 
50 impl SideEffect {
new() -> SideEffect51     fn new() -> SideEffect {
52         SideEffect(0)
53     }
next(&mut self) -> i3254     fn next(&mut self) -> i32 {
55         self.0 += 1;
56         self.0
57     }
58 }
59 
main()60 fn main() {
61     // wrong, produces first error in stderr
62     let mut a: A = Default::default();
63     a.i = 42;
64 
65     // right
66     let mut a: A = Default::default();
67 
68     // right
69     let a = A {
70         i: 42,
71         ..Default::default()
72     };
73 
74     // right
75     let mut a: A = Default::default();
76     if a.i == 0 {
77         a.j = 12;
78     }
79 
80     // right
81     let mut a: A = Default::default();
82     let b = 5;
83 
84     // right
85     let mut b = 32;
86     let mut a: A = Default::default();
87     b = 2;
88 
89     // right
90     let b: B = B { i: 42, j: 24 };
91 
92     // right
93     let mut b: B = B { i: 42, j: 24 };
94     b.i = 52;
95 
96     // right
97     let mut b = B { i: 15, j: 16 };
98     let mut a: A = Default::default();
99     b.i = 2;
100 
101     // wrong, produces second error in stderr
102     let mut a: A = Default::default();
103     a.j = 43;
104     a.i = 42;
105 
106     // wrong, produces third error in stderr
107     let mut a: A = Default::default();
108     a.i = 42;
109     a.j = 43;
110     a.j = 44;
111 
112     // wrong, produces fourth error in stderr
113     let mut a = A::default();
114     a.i = 42;
115 
116     // wrong, but does not produce an error in stderr, because we can't produce a correct kind of
117     // suggestion with current implementation
118     let mut c: (i32, i32) = Default::default();
119     c.0 = 42;
120     c.1 = 21;
121 
122     // wrong, produces the fifth error in stderr
123     let mut a: A = Default::default();
124     a.i = Default::default();
125 
126     // wrong, produces the sixth error in stderr
127     let mut a: A = Default::default();
128     a.i = Default::default();
129     a.j = 45;
130 
131     // right, because an assignment refers to another field
132     let mut x = A::default();
133     x.i = 42;
134     x.j = 21 + x.i as i64;
135 
136     // right, we bail out if there's a reassignment to the same variable, since there is a risk of
137     // side-effects affecting the outcome
138     let mut x = A::default();
139     let mut side_effect = SideEffect::new();
140     x.i = side_effect.next();
141     x.j = 2;
142     x.i = side_effect.next();
143 
144     // don't lint - some private fields
145     let mut x = m::F::default();
146     x.a = 1;
147 
148     // don't expand macros in the suggestion (#6522)
149     let mut a: C = C::default();
150     a.i = vec![1];
151 
152     // Don't lint in external macros
153     field_reassign_with_default!();
154 
155     // be sure suggestion is correct with generics
156     let mut a: Wrapper<bool> = Default::default();
157     a.i = true;
158 
159     let mut a: WrapperMulti<i32, i64> = Default::default();
160     a.i = 42;
161 
162     // Don't lint in macros
163     m! {
164         a: 42
165     };
166 }
167 
168 mod m {
169     #[derive(Default)]
170     pub struct F {
171         pub a: u64,
172         b: u64,
173     }
174 }
175 
176 #[derive(Default)]
177 struct Wrapper<T> {
178     i: T,
179 }
180 
181 #[derive(Default)]
182 struct WrapperMulti<T, U> {
183     i: T,
184     j: U,
185 }
186 
187 mod issue6312 {
188     use std::sync::atomic::AtomicBool;
189     use std::sync::Arc;
190 
191     // do not lint: type implements `Drop` but not all fields are `Copy`
192     #[derive(Clone, Default)]
193     pub struct ImplDropNotAllCopy {
194         name: String,
195         delay_data_sync: Arc<AtomicBool>,
196     }
197 
198     impl Drop for ImplDropNotAllCopy {
drop(&mut self)199         fn drop(&mut self) {
200             self.close()
201         }
202     }
203 
204     impl ImplDropNotAllCopy {
new(name: &str) -> Self205         fn new(name: &str) -> Self {
206             let mut f = ImplDropNotAllCopy::default();
207             f.name = name.to_owned();
208             f
209         }
close(&self)210         fn close(&self) {}
211     }
212 
213     // lint: type implements `Drop` and all fields are `Copy`
214     #[derive(Clone, Default)]
215     pub struct ImplDropAllCopy {
216         name: usize,
217         delay_data_sync: bool,
218     }
219 
220     impl Drop for ImplDropAllCopy {
drop(&mut self)221         fn drop(&mut self) {
222             self.close()
223         }
224     }
225 
226     impl ImplDropAllCopy {
new(name: &str) -> Self227         fn new(name: &str) -> Self {
228             let mut f = ImplDropAllCopy::default();
229             f.name = name.len();
230             f
231         }
close(&self)232         fn close(&self) {}
233     }
234 
235     // lint: type does not implement `Drop` though all fields are `Copy`
236     #[derive(Clone, Default)]
237     pub struct NoDropAllCopy {
238         name: usize,
239         delay_data_sync: bool,
240     }
241 
242     impl NoDropAllCopy {
new(name: &str) -> Self243         fn new(name: &str) -> Self {
244             let mut f = NoDropAllCopy::default();
245             f.name = name.len();
246             f
247         }
248     }
249 }
250