1 | // RUN: %check_clang_tidy %s modernize-use-equals-default %t -- \ |
2 | // RUN: -config="{CheckOptions: {modernize-use-equals-default.IgnoreMacros: false}}" \ |
3 | // RUN: -- -fno-delayed-template-parsing -fexceptions |
4 | |
5 | // Out of line definition. |
6 | struct OL { |
7 | OL(const OL &); |
8 | OL &operator=(const OL &); |
9 | int Field; |
10 | }; |
11 | OL::OL(const OL &Other) : Field(Other.Field) {} |
12 | // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default' to define a trivial copy constructor [modernize-use-equals-default] |
13 | // CHECK-FIXES: OL::OL(const OL &Other) = default; |
14 | OL &OL::operator=(const OL &Other) { |
15 | Field = Other.Field; |
16 | return *this; |
17 | } |
18 | // CHECK-MESSAGES: :[[@LINE-4]]:9: warning: use '= default' to define a trivial copy-assignment operator [modernize-use-equals-default] |
19 | // CHECK-FIXES: OL &OL::operator=(const OL &Other) = default; |
20 | |
21 | // Inline. |
22 | struct IL { |
23 | IL(const IL &Other) : Field(Other.Field) {} |
24 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' |
25 | // CHECK-FIXES: IL(const IL &Other) = default; |
26 | IL &operator=(const IL &Other) { |
27 | Field = Other.Field; |
28 | return *this; |
29 | } |
30 | // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use '= default' |
31 | // CHECK-FIXES: IL &operator=(const IL &Other) = default; |
32 | int Field; |
33 | }; |
34 | |
35 | // Skip unions. |
36 | union NU { |
37 | NU(const NU &Other) : Field(Other.Field) {} |
38 | // CHECK-FIXES: NU(const NU &Other) : |
39 | NU &operator=(const NU &Other) { |
40 | Field = Other.Field; |
41 | return *this; |
42 | } |
43 | // CHECK-FIXES: NU &operator=(const NU &Other) { |
44 | IL Field; |
45 | }; |
46 | |
47 | // Skip structs/classes containing anonymous unions. |
48 | struct SU { |
49 | SU(const SU &Other) : Field(Other.Field) {} |
50 | // CHECK-FIXES: SU(const SU &Other) : |
51 | SU &operator=(const SU &Other) { |
52 | Field = Other.Field; |
53 | return *this; |
54 | } |
55 | // CHECK-FIXES: SU &operator=(const SU &Other) { |
56 | union { |
57 | IL Field; |
58 | }; |
59 | }; |
60 | |
61 | // Wrong type. |
62 | struct WT { |
63 | WT(const IL &Other) {} |
64 | WT &operator=(const IL &); |
65 | }; |
66 | WT &WT::operator=(const IL &Other) { return *this; } |
67 | |
68 | // Qualifiers. |
69 | struct Qual { |
70 | Qual(const Qual &Other) : Field(Other.Field), Volatile(Other.Volatile), |
71 | Mutable(Other.Mutable), Reference(Other.Reference), |
72 | Const(Other.Const) {} |
73 | // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use '= default' |
74 | // CHECK-FIXES: Qual(const Qual &Other) |
75 | // CHECK-FIXES: = default; |
76 | |
77 | int Field; |
78 | volatile char Volatile; |
79 | mutable bool Mutable; |
80 | const OL &Reference; // This makes this class non-assignable. |
81 | const IL Const; // This also makes this class non-assignable. |
82 | static int Static; |
83 | }; |
84 | |
85 | // Wrong init arguments. |
86 | struct WI { |
87 | WI(const WI &Other) : Field1(Other.Field1), Field2(Other.Field1) {} |
88 | WI &operator=(const WI &); |
89 | int Field1, Field2; |
90 | }; |
91 | WI &WI::operator=(const WI &Other) { |
92 | Field1 = Other.Field1; |
93 | Field2 = Other.Field1; |
94 | return *this; |
95 | } |
96 | |
97 | // Missing field. |
98 | struct MF { |
99 | MF(const MF &Other) : Field1(Other.Field1), Field2(Other.Field2) {} |
100 | MF &operator=(const MF &); |
101 | int Field1, Field2, Field3; |
102 | }; |
103 | MF &MF::operator=(const MF &Other) { |
104 | Field1 = Other.Field1; |
105 | Field2 = Other.Field2; |
106 | return *this; |
107 | } |
108 | |
109 | struct { |
110 | (const Comments &Other) |
111 | /* don't delete */ : /* this comment */ Field(Other.Field) {} |
112 | // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default' |
113 | // CHECK-FIXES: /* don't delete */ = default; |
114 | int ; |
115 | }; |
116 | |
117 | struct { |
118 | (const MoreComments &Other) /* this comment is OK */ |
119 | : Field(Other.Field) {} |
120 | // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default' |
121 | // CHECK-FIXES: MoreComments(const MoreComments &Other) /* this comment is OK */ |
122 | // CHECK-FIXES-NEXT: = default; |
123 | int ; |
124 | }; |
125 | |
126 | struct { |
127 | (const ColonInComment &Other) /* : */ : Field(Other.Field) {} |
128 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' |
129 | // CHECK-FIXES: ColonInComment(const ColonInComment &Other) /* : */ = default; |
130 | int ; |
131 | }; |
132 | |
133 | // No members or bases (in particular, no colon). |
134 | struct Empty { |
135 | Empty(const Empty &Other) {} |
136 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' |
137 | // CHECK-FIXES: Empty(const Empty &Other) = default; |
138 | Empty &operator=(const Empty &); |
139 | }; |
140 | Empty &Empty::operator=(const Empty &Other) { return *this; } |
141 | // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use '= default' |
142 | // CHECK-FIXES: Empty &Empty::operator=(const Empty &Other) = default; |
143 | |
144 | // Bit fields. |
145 | struct BF { |
146 | BF() = default; |
147 | BF(const BF &Other) : Field1(Other.Field1), Field2(Other.Field2), Field3(Other.Field3), |
148 | Field4(Other.Field4) {}; |
149 | // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default' |
150 | // CHECK-FIXES: BF(const BF &Other) {{$}} |
151 | // CHECK-FIXES: = default; |
152 | BF &operator=(const BF &); |
153 | |
154 | unsigned Field1 : 3; |
155 | int : 7; |
156 | char Field2 : 6; |
157 | int : 0; |
158 | int Field3 : 24; |
159 | unsigned char Field4; |
160 | }; |
161 | BF &BF::operator=(const BF &Other) { |
162 | Field1 = Other.Field1; |
163 | Field2 = Other.Field2; |
164 | Field3 = Other.Field3; |
165 | Field4 = Other.Field4; |
166 | return *this; |
167 | } |
168 | // CHECK-MESSAGES: :[[@LINE-7]]:9: warning: use '= default' |
169 | // CHECK-FIXES: BF &BF::operator=(const BF &Other) = default; |
170 | |
171 | // Base classes. |
172 | struct BC : IL, OL, BF { |
173 | BC(const BC &Other) : IL(Other), OL(Other), BF(Other) {} |
174 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' |
175 | // CHECK-FIXES: BC(const BC &Other) = default; |
176 | BC &operator=(const BC &Other); |
177 | }; |
178 | BC &BC::operator=(const BC &Other) { |
179 | IL::operator=(Other); |
180 | OL::operator=(Other); |
181 | BF::operator=(Other); |
182 | return *this; |
183 | } |
184 | // CHECK-MESSAGES: :[[@LINE-6]]:9: warning: use '= default' |
185 | // CHECK-FIXES: BC &BC::operator=(const BC &Other) = default; |
186 | |
187 | // Base classes with member. |
188 | struct BCWM : IL, OL { |
189 | BCWM(const BCWM &Other) : IL(Other), OL(Other), Bf(Other.Bf) {} |
190 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' |
191 | // CHECK-FIXES: BCWM(const BCWM &Other) = default; |
192 | BCWM &operator=(const BCWM &); |
193 | BF Bf; |
194 | }; |
195 | BCWM &BCWM::operator=(const BCWM &Other) { |
196 | IL::operator=(Other); |
197 | OL::operator=(Other); |
198 | Bf = Other.Bf; |
199 | return *this; |
200 | } |
201 | // CHECK-MESSAGES: :[[@LINE-6]]:13: warning: use '= default' |
202 | // CHECK-FIXES: BCWM &BCWM::operator=(const BCWM &Other) = default; |
203 | |
204 | // Missing base class. |
205 | struct MBC : IL, OL, BF { |
206 | MBC(const MBC &Other) : IL(Other), OL(Other) {} |
207 | MBC &operator=(const MBC &); |
208 | }; |
209 | MBC &MBC::operator=(const MBC &Other) { |
210 | IL::operator=(Other); |
211 | OL::operator=(Other); |
212 | return *this; |
213 | } |
214 | |
215 | // Base classes, incorrect parameter. |
216 | struct BCIP : BCWM, BF { |
217 | BCIP(const BCIP &Other) : BCWM(Other), BF(Other.Bf) {} |
218 | BCIP &operator=(const BCIP &); |
219 | }; |
220 | BCIP &BCIP::operator=(const BCIP &Other) { |
221 | BCWM::operator=(Other); |
222 | BF::operator=(Other: Other.Bf); |
223 | return *this; |
224 | } |
225 | |
226 | // Virtual base classes. |
227 | struct VA : virtual OL {}; |
228 | struct VB : virtual OL {}; |
229 | struct VBC : VA, VB, virtual OL { |
230 | // OL is the first thing that is going to be initialized, despite the fact |
231 | // that it is the last in the list of bases, because it is virtual and there |
232 | // is a virtual OL at the beginning of VA (which is the same). |
233 | VBC(const VBC &Other) : OL(Other), VA(Other), VB(Other) {} |
234 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' |
235 | // CHECK-FIXES: VBC(const VBC &Other) = default; |
236 | VBC &operator=(const VBC &Other); |
237 | }; |
238 | VBC &VBC::operator=(const VBC &Other) { |
239 | OL::operator=(Other); |
240 | VA::operator=(Other); |
241 | VB::operator=(Other); |
242 | return *this; |
243 | } |
244 | // CHECK-MESSAGES: :[[@LINE-6]]:11: warning: use '= default' |
245 | // CHECK-FIXES: VBC &VBC::operator=(const VBC &Other) = default; |
246 | |
247 | // Indirect base. |
248 | struct IB : VBC { |
249 | IB(const IB &Other) : OL(Other), VBC(Other) {} |
250 | IB &operator=(const IB &); |
251 | }; |
252 | IB &IB::operator=(const IB &Other) { |
253 | OL::operator=(Other); |
254 | VBC::operator=(Other); |
255 | return *this; |
256 | } |
257 | |
258 | // Class template. |
259 | template <class T> |
260 | struct Template { |
261 | Template() = default; |
262 | Template(const Template &Other) : Field(Other.Field) {} |
263 | Template &operator=(const Template &Other); |
264 | void foo(const T &t); |
265 | int Field; |
266 | }; |
267 | template <class T> |
268 | Template<T> &Template<T>::operator=(const Template<T> &Other) { |
269 | Field = Other.Field; |
270 | return *this; |
271 | } |
272 | Template<int> T1; |
273 | |
274 | // Dependent types. |
275 | template <class T> |
276 | struct DT1 { |
277 | DT1() = default; |
278 | DT1(const DT1 &Other) : Field(Other.Field) {} |
279 | DT1 &operator=(const DT1 &); |
280 | T Field; |
281 | }; |
282 | template <class T> |
283 | DT1<T> &DT1<T>::operator=(const DT1<T> &Other) { |
284 | Field = Other.Field; |
285 | return *this; |
286 | } |
287 | DT1<int> Dt1; |
288 | |
289 | template <class T> |
290 | struct DT2 { |
291 | DT2() = default; |
292 | DT2(const DT2 &Other) : Field(Other.Field), Dependent(Other.Dependent) {} |
293 | DT2 &operator=(const DT2 &); |
294 | T Field; |
295 | typename T::TT Dependent; |
296 | }; |
297 | template <class T> |
298 | DT2<T> &DT2<T>::operator=(const DT2<T> &Other) { |
299 | Field = Other.Field; |
300 | Dependent = Other.Dependent; |
301 | return *this; |
302 | } |
303 | struct T { |
304 | typedef int TT; |
305 | }; |
306 | DT2<T> Dt2; |
307 | |
308 | // Default arguments. |
309 | struct DA { |
310 | DA(int Int); |
311 | DA(const DA &Other = DA(0)) : Field1(Other.Field1), Field2(Other.Field2) {} |
312 | DA &operator=(const DA &); |
313 | int Field1; |
314 | char Field2; |
315 | }; |
316 | // Overloaded operator= cannot have a default argument. |
317 | DA &DA::operator=(const DA &Other) { |
318 | Field1 = Other.Field1; |
319 | Field2 = Other.Field2; |
320 | return *this; |
321 | } |
322 | // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: use '= default' |
323 | // CHECK-FIXES: DA &DA::operator=(const DA &Other) = default; |
324 | |
325 | struct DA2 { |
326 | // Can be used as copy-constructor but cannot be explicitly defaulted. |
327 | DA2(const DA &Other, int Def = 0) {} |
328 | }; |
329 | |
330 | // Default initialization. |
331 | struct DI { |
332 | DI(const DI &Other) : Field1(Other.Field1), Field2(Other.Field2) {} |
333 | int Field1; |
334 | int Field2 = 0; |
335 | int Fiedl3; |
336 | }; |
337 | |
338 | // Statement inside body. |
339 | void foo(); |
340 | struct SIB { |
341 | SIB(const SIB &Other) : Field(Other.Field) { foo(); } |
342 | SIB &operator=(const SIB &); |
343 | int Field; |
344 | }; |
345 | SIB &SIB::operator=(const SIB &Other) { |
346 | Field = Other.Field; |
347 | foo(); |
348 | return *this; |
349 | } |
350 | |
351 | // Comment inside body. |
352 | struct CIB { |
353 | CIB(const CIB &Other) : Field(Other.Field) { /* Don't erase this */ |
354 | } |
355 | // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default' |
356 | CIB &operator=(const CIB &); |
357 | int Field; |
358 | }; |
359 | CIB &CIB::operator=(const CIB &Other) { |
360 | Field = Other.Field; |
361 | // FIXME: don't erase this comment. |
362 | return *this; |
363 | } |
364 | // CHECK-MESSAGES: :[[@LINE-5]]:11: warning: use '= default' |
365 | // CHECK-FIXES: CIB &CIB::operator=(const CIB &Other) = default; |
366 | |
367 | // Take non-const reference as argument. |
368 | struct NCRef { |
369 | NCRef(NCRef &Other) : Field1(Other.Field1), Field2(Other.Field2) {} |
370 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' |
371 | // CHECK-FIXES: NCRef(NCRef &Other) = default; |
372 | NCRef &operator=(NCRef &); |
373 | int Field1, Field2; |
374 | }; |
375 | NCRef &NCRef::operator=(NCRef &Other) { |
376 | Field1 = Other.Field1; |
377 | Field2 = Other.Field2; |
378 | return *this; |
379 | } |
380 | // CHECK-MESSAGES: :[[@LINE-5]]:15: warning: use '= default' |
381 | // CHECK-FIXES: NCRef &NCRef::operator=(NCRef &Other) = default; |
382 | |
383 | // Already defaulted. |
384 | struct IAD { |
385 | IAD(const IAD &Other) = default; |
386 | IAD &operator=(const IAD &Other) = default; |
387 | }; |
388 | |
389 | struct OAD { |
390 | OAD(const OAD &Other); |
391 | OAD &operator=(const OAD &); |
392 | }; |
393 | OAD::OAD(const OAD &Other) = default; |
394 | OAD &OAD::operator=(const OAD &Other) = default; |
395 | |
396 | // Deleted. |
397 | struct ID { |
398 | ID(const ID &Other) = delete; |
399 | ID &operator=(const ID &Other) = delete; |
400 | }; |
401 | |
402 | // Non-reference parameter. |
403 | struct NRef { |
404 | NRef &operator=(NRef Other); |
405 | int Field1; |
406 | }; |
407 | NRef &NRef::operator=(NRef Other) { |
408 | Field1 = Other.Field1; |
409 | return *this; |
410 | } |
411 | |
412 | // RValue reference parameter. |
413 | struct RVR { |
414 | RVR(RVR &&Other) {} |
415 | RVR &operator=(RVR &&); |
416 | }; |
417 | RVR &RVR::operator=(RVR &&Other) { return *this; } |
418 | |
419 | // Similar function. |
420 | struct SF { |
421 | SF &foo(const SF &); |
422 | int Field1; |
423 | }; |
424 | SF &SF::foo(const SF &Other) { |
425 | Field1 = Other.Field1; |
426 | return *this; |
427 | } |
428 | |
429 | // No return. |
430 | struct NR { |
431 | NR &operator=(const NR &); |
432 | }; |
433 | NR &NR::operator=(const NR &Other) {} |
434 | |
435 | // Return misplaced. |
436 | struct RM { |
437 | RM &operator=(const RM &); |
438 | int Field; |
439 | }; |
440 | RM &RM::operator=(const RM &Other) { |
441 | return *this; |
442 | Field = Other.Field; |
443 | } |
444 | |
445 | // Wrong return value. |
446 | struct WRV { |
447 | WRV &operator=(WRV &); |
448 | }; |
449 | WRV &WRV::operator=(WRV &Other) { |
450 | return Other; |
451 | } |
452 | |
453 | // Wrong return type. |
454 | struct WRT : IL { |
455 | IL &operator=(const WRT &); |
456 | }; |
457 | IL &WRT::operator=(const WRT &Other) { |
458 | return *this; |
459 | } |
460 | |
461 | // Wrong return type. |
462 | struct WRTConstRef { |
463 | const WRTConstRef &operator = (const WRTConstRef &) { |
464 | return *this; |
465 | } |
466 | }; |
467 | |
468 | // Try-catch. |
469 | struct ITC { |
470 | ITC(const ITC &Other) |
471 | try : Field(Other.Field) { |
472 | } catch (...) { |
473 | } |
474 | ITC &operator=(const ITC &Other) try { |
475 | Field = Other.Field; |
476 | } catch (...) { |
477 | } |
478 | int Field; |
479 | }; |
480 | |
481 | struct OTC { |
482 | OTC(const OTC &); |
483 | OTC &operator=(const OTC &); |
484 | int Field; |
485 | }; |
486 | OTC::OTC(const OTC &Other) try : Field(Other.Field) { |
487 | } catch (...) { |
488 | } |
489 | OTC &OTC::operator=(const OTC &Other) try { |
490 | Field = Other.Field; |
491 | } catch (...) { |
492 | } |
493 | |
494 | // FIXME: the check is not able to detect exception specification. |
495 | // noexcept(true). |
496 | struct NET { |
497 | // This is the default. |
498 | //NET(const NET &Other) noexcept {} |
499 | NET &operator=(const NET &Other) noexcept; |
500 | }; |
501 | //NET &NET::operator=(const NET &Other) noexcept { return *this; } |
502 | |
503 | // noexcept(false). |
504 | struct NEF { |
505 | // This is the default. |
506 | //NEF(const NEF &Other) noexcept(false) {} |
507 | NEF &operator=(const NEF &Other) noexcept(false); |
508 | }; |
509 | //NEF &NEF::operator=(const NEF &Other) noexcept(false) { return *this; } |
510 | |
511 | #define STRUCT_WITH_COPY_CONSTRUCT(_base, _type) \ |
512 | struct _type { \ |
513 | _type(const _type &v) : value(v.value) {} \ |
514 | _base value; \ |
515 | }; |
516 | |
517 | STRUCT_WITH_COPY_CONSTRUCT(unsigned char, Hex8CopyConstruct) |
518 | // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial copy constructor |
519 | // CHECK-MESSAGES: :[[@LINE-6]]:44: note: |
520 | |
521 | #define STRUCT_WITH_COPY_ASSIGN(_base, _type) \ |
522 | struct _type { \ |
523 | _type &operator=(const _type &rhs) { \ |
524 | value = rhs.value; \ |
525 | return *this; \ |
526 | } \ |
527 | _base value; \ |
528 | }; |
529 | |
530 | STRUCT_WITH_COPY_ASSIGN(unsigned char, Hex8CopyAssign) |
531 | // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial copy-assignment operator |
532 | // CHECK-MESSAGES: :[[@LINE-9]]:40: note: |
533 | |
534 | // Use of braces |
535 | struct UOB{ |
536 | UOB(const UOB &Other):j{Other.j}{} |
537 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' to define a trivial copy constructor [modernize-use-equals-default] |
538 | // CHECK-FIXES: UOB(const UOB &Other)= default; |
539 | int j; |
540 | }; |
541 | |