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