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.
6struct OL {
7 OL(const OL &);
8 OL &operator=(const OL &);
9 int Field;
10};
11OL::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;
14OL &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.
22struct 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.
36union 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.
48struct 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.
62struct WT {
63 WT(const IL &Other) {}
64 WT &operator=(const IL &);
65};
66WT &WT::operator=(const IL &Other) { return *this; }
67
68// Qualifiers.
69struct 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.
86struct WI {
87 WI(const WI &Other) : Field1(Other.Field1), Field2(Other.Field1) {}
88 WI &operator=(const WI &);
89 int Field1, Field2;
90};
91WI &WI::operator=(const WI &Other) {
92 Field1 = Other.Field1;
93 Field2 = Other.Field1;
94 return *this;
95}
96
97// Missing field.
98struct MF {
99 MF(const MF &Other) : Field1(Other.Field1), Field2(Other.Field2) {}
100 MF &operator=(const MF &);
101 int Field1, Field2, Field3;
102};
103MF &MF::operator=(const MF &Other) {
104 Field1 = Other.Field1;
105 Field2 = Other.Field2;
106 return *this;
107}
108
109struct Comments {
110 Comments(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 Field;
115};
116
117struct MoreComments {
118 MoreComments(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 Field;
124};
125
126struct ColonInComment {
127 ColonInComment(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 Field;
131};
132
133// No members or bases (in particular, no colon).
134struct 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};
140Empty &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.
145struct 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};
161BF &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.
172struct 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};
178BC &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.
188struct 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};
195BCWM &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.
205struct MBC : IL, OL, BF {
206 MBC(const MBC &Other) : IL(Other), OL(Other) {}
207 MBC &operator=(const MBC &);
208};
209MBC &MBC::operator=(const MBC &Other) {
210 IL::operator=(Other);
211 OL::operator=(Other);
212 return *this;
213}
214
215// Base classes, incorrect parameter.
216struct BCIP : BCWM, BF {
217 BCIP(const BCIP &Other) : BCWM(Other), BF(Other.Bf) {}
218 BCIP &operator=(const BCIP &);
219};
220BCIP &BCIP::operator=(const BCIP &Other) {
221 BCWM::operator=(Other);
222 BF::operator=(Other: Other.Bf);
223 return *this;
224}
225
226// Virtual base classes.
227struct VA : virtual OL {};
228struct VB : virtual OL {};
229struct 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};
238VBC &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.
248struct IB : VBC {
249 IB(const IB &Other) : OL(Other), VBC(Other) {}
250 IB &operator=(const IB &);
251};
252IB &IB::operator=(const IB &Other) {
253 OL::operator=(Other);
254 VBC::operator=(Other);
255 return *this;
256}
257
258// Class template.
259template <class T>
260struct 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};
267template <class T>
268Template<T> &Template<T>::operator=(const Template<T> &Other) {
269 Field = Other.Field;
270 return *this;
271}
272Template<int> T1;
273
274// Dependent types.
275template <class T>
276struct DT1 {
277 DT1() = default;
278 DT1(const DT1 &Other) : Field(Other.Field) {}
279 DT1 &operator=(const DT1 &);
280 T Field;
281};
282template <class T>
283DT1<T> &DT1<T>::operator=(const DT1<T> &Other) {
284 Field = Other.Field;
285 return *this;
286}
287DT1<int> Dt1;
288
289template <class T>
290struct 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};
297template <class T>
298DT2<T> &DT2<T>::operator=(const DT2<T> &Other) {
299 Field = Other.Field;
300 Dependent = Other.Dependent;
301 return *this;
302}
303struct T {
304 typedef int TT;
305};
306DT2<T> Dt2;
307
308// Default arguments.
309struct 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.
317DA &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
325struct 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.
331struct 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.
339void foo();
340struct SIB {
341 SIB(const SIB &Other) : Field(Other.Field) { foo(); }
342 SIB &operator=(const SIB &);
343 int Field;
344};
345SIB &SIB::operator=(const SIB &Other) {
346 Field = Other.Field;
347 foo();
348 return *this;
349}
350
351// Comment inside body.
352struct 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};
359CIB &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.
368struct 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};
375NCRef &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.
384struct IAD {
385 IAD(const IAD &Other) = default;
386 IAD &operator=(const IAD &Other) = default;
387};
388
389struct OAD {
390 OAD(const OAD &Other);
391 OAD &operator=(const OAD &);
392};
393OAD::OAD(const OAD &Other) = default;
394OAD &OAD::operator=(const OAD &Other) = default;
395
396// Deleted.
397struct ID {
398 ID(const ID &Other) = delete;
399 ID &operator=(const ID &Other) = delete;
400};
401
402// Non-reference parameter.
403struct NRef {
404 NRef &operator=(NRef Other);
405 int Field1;
406};
407NRef &NRef::operator=(NRef Other) {
408 Field1 = Other.Field1;
409 return *this;
410}
411
412// RValue reference parameter.
413struct RVR {
414 RVR(RVR &&Other) {}
415 RVR &operator=(RVR &&);
416};
417RVR &RVR::operator=(RVR &&Other) { return *this; }
418
419// Similar function.
420struct SF {
421 SF &foo(const SF &);
422 int Field1;
423};
424SF &SF::foo(const SF &Other) {
425 Field1 = Other.Field1;
426 return *this;
427}
428
429// No return.
430struct NR {
431 NR &operator=(const NR &);
432};
433NR &NR::operator=(const NR &Other) {}
434
435// Return misplaced.
436struct RM {
437 RM &operator=(const RM &);
438 int Field;
439};
440RM &RM::operator=(const RM &Other) {
441 return *this;
442 Field = Other.Field;
443}
444
445// Wrong return value.
446struct WRV {
447 WRV &operator=(WRV &);
448};
449WRV &WRV::operator=(WRV &Other) {
450 return Other;
451}
452
453// Wrong return type.
454struct WRT : IL {
455 IL &operator=(const WRT &);
456};
457IL &WRT::operator=(const WRT &Other) {
458 return *this;
459}
460
461// Wrong return type.
462struct WRTConstRef {
463 const WRTConstRef &operator = (const WRTConstRef &) {
464 return *this;
465 }
466};
467
468// Try-catch.
469struct 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
481struct OTC {
482 OTC(const OTC &);
483 OTC &operator=(const OTC &);
484 int Field;
485};
486OTC::OTC(const OTC &Other) try : Field(Other.Field) {
487} catch (...) {
488}
489OTC &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).
496struct 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).
504struct 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
517STRUCT_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
530STRUCT_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
535struct 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

source code of clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp