xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/modernize/use-equals-default-copy.cpp (revision 8009bbec59d1c5d47ae06c431647ebee6d886ff2)
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 };
OL(const OL & Other)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;
operator =(const OL & Other)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 {
ILIL23   IL(const IL &Other) : Field(Other.Field) {}
24   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
25   // CHECK-FIXES: IL(const IL &Other)  = default;
operator =IL26   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 {
NU(const NU & Other)37   NU(const NU &Other) : Field(Other.Field) {}
38   // CHECK-FIXES: NU(const NU &Other) :
operator =(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 {
SUSU49   SU(const SU &Other) : Field(Other.Field) {}
50   // CHECK-FIXES: SU(const SU &Other) :
operator =SU51   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 {
WTWT63   WT(const IL &Other) {}
64   WT &operator=(const IL &);
65 };
operator =(const IL & Other)66 WT &WT::operator=(const IL &Other) { return *this; }
67 
68 // Qualifiers.
69 struct Qual {
QualQual70   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 {
WIWI87   WI(const WI &Other) : Field1(Other.Field1), Field2(Other.Field1) {}
88   WI &operator=(const WI &);
89   int Field1, Field2;
90 };
operator =(const WI & Other)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 {
MFMF99   MF(const MF &Other) : Field1(Other.Field1), Field2(Other.Field2) {}
100   MF &operator=(const MF &);
101   int Field1, Field2, Field3;
102 };
operator =(const MF & Other)103 MF &MF::operator=(const MF &Other) {
104   Field1 = Other.Field1;
105   Field2 = Other.Field2;
106   return *this;
107 }
108 
109 struct Comments {
CommentsComments110   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 
117 struct MoreComments {
MoreCommentsMoreComments118   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 
126 struct ColonInComment {
ColonInCommentColonInComment127   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).
134 struct Empty {
EmptyEmpty135   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 };
operator =(const Empty & Other)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;
BFBF147   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 };
operator =(const BF & Other)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 {
BCBC173   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 };
operator =(const BC & Other)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 {
BCWMBCWM189   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 };
operator =(const BCWM & Other)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 {
MBCMBC206   MBC(const MBC &Other) : IL(Other), OL(Other) {}
207   MBC &operator=(const MBC &);
208 };
operator =(const MBC & Other)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 {
BCIPBCIP217   BCIP(const BCIP &Other) : BCWM(Other), BF(Other.Bf) {}
218   BCIP &operator=(const BCIP &);
219 };
operator =(const BCIP & Other)220 BCIP &BCIP::operator=(const BCIP &Other) {
221   BCWM::operator=(Other);
222   BF::operator=(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).
VBCVBC233   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 };
operator =(const VBC & Other)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 {
IBIB249   IB(const IB &Other) : OL(Other), VBC(Other) {}
250   IB &operator=(const IB &);
251 };
operator =(const IB & Other)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;
TemplateTemplate262   Template(const Template &Other) : Field(Other.Field) {}
263   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
264   // CHECK-FIXES: Template(const Template &Other)  = default;
265   Template &operator=(const Template &Other);
266   void foo(const T &t);
267   int Field;
268 };
269 template <class T>
operator =(const Template<T> & Other)270 Template<T> &Template<T>::operator=(const Template<T> &Other) {
271   Field = Other.Field;
272   return *this;
273 }
274 // CHECK-MESSAGES: :[[@LINE-4]]:27: warning: use '= default'
275 // CHECK-FIXES: Template<T> &Template<T>::operator=(const Template<T> &Other) = default;
276 
277 Template<int> T1;
278 
279 
280 // Dependent types.
281 template <class T>
282 struct DT1 {
283   DT1() = default;
DT1DT1284   DT1(const DT1 &Other) : Field(Other.Field) {}
285   DT1 &operator=(const DT1 &);
286   T Field;
287 };
288 template <class T>
operator =(const DT1<T> & Other)289 DT1<T> &DT1<T>::operator=(const DT1<T> &Other) {
290   Field = Other.Field;
291   return *this;
292 }
293 // CHECK-MESSAGES: :[[@LINE-4]]:17: warning: use '= default'
294 // CHECK-FIXES: DT1<T> &DT1<T>::operator=(const DT1<T> &Other) = default;
295 
296 DT1<int> Dt1;
297 
298 template <class T>
299 struct DT2 {
300   DT2() = default;
DT2DT2301   DT2(const DT2 &Other) : Field(Other.Field), Dependent(Other.Dependent) {}
302   DT2 &operator=(const DT2 &);
303   T Field;
304   typename T::TT Dependent;
305 };
306 template <class T>
operator =(const DT2<T> & Other)307 DT2<T> &DT2<T>::operator=(const DT2<T> &Other) {
308   Field = Other.Field;
309   Dependent = Other.Dependent;
310   return *this;
311 }
312 struct T {
313   typedef int TT;
314 };
315 // CHECK-MESSAGES: :[[@LINE-8]]:17: warning: use '= default'
316 // CHECK-FIXES: DT2<T> &DT2<T>::operator=(const DT2<T> &Other) = default;
317 
318 DT2<T> Dt2;
319 
320 // Default arguments.
321 struct DA {
322   DA(int Int);
DADA323   DA(const DA &Other = DA(0)) : Field1(Other.Field1), Field2(Other.Field2) {}
324   DA &operator=(const DA &);
325   int Field1;
326   char Field2;
327 };
328 // Overloaded operator= cannot have a default argument.
operator =(const DA & Other)329 DA &DA::operator=(const DA &Other) {
330   Field1 = Other.Field1;
331   Field2 = Other.Field2;
332   return *this;
333 }
334 // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: use '= default'
335 // CHECK-FIXES: DA &DA::operator=(const DA &Other) = default;
336 
337 struct DA2 {
338   // Can be used as copy-constructor but cannot be explicitly defaulted.
DA2DA2339   DA2(const DA &Other, int Def = 0) {}
340 };
341 
342 // Default initialization.
343 struct DI {
DIDI344   DI(const DI &Other) : Field1(Other.Field1), Field2(Other.Field2) {}
345   int Field1;
346   int Field2 = 0;
347   int Fiedl3;
348 };
349 
350 // Statement inside body.
351 void foo();
352 struct SIB {
SIBSIB353   SIB(const SIB &Other) : Field(Other.Field) { foo(); }
354   SIB &operator=(const SIB &);
355   int Field;
356 };
operator =(const SIB & Other)357 SIB &SIB::operator=(const SIB &Other) {
358   Field = Other.Field;
359   foo();
360   return *this;
361 }
362 
363 // Comment inside body.
364 struct CIB {
CIBCIB365   CIB(const CIB &Other) : Field(Other.Field) { /* Don't erase this */
366   }
367   // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default'
368   CIB &operator=(const CIB &);
369   int Field;
370 };
operator =(const CIB & Other)371 CIB &CIB::operator=(const CIB &Other) {
372   Field = Other.Field;
373   // FIXME: don't erase this comment.
374   return *this;
375 }
376 // CHECK-MESSAGES: :[[@LINE-5]]:11: warning: use '= default'
377 // CHECK-FIXES: CIB &CIB::operator=(const CIB &Other) = default;
378 
379 // Take non-const reference as argument.
380 struct NCRef {
NCRefNCRef381   NCRef(NCRef &Other) : Field1(Other.Field1), Field2(Other.Field2) {}
382   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default'
383   // CHECK-FIXES: NCRef(NCRef &Other)  = default;
384   NCRef &operator=(NCRef &);
385   int Field1, Field2;
386 };
operator =(NCRef & Other)387 NCRef &NCRef::operator=(NCRef &Other) {
388   Field1 = Other.Field1;
389   Field2 = Other.Field2;
390   return *this;
391 }
392 // CHECK-MESSAGES: :[[@LINE-5]]:15: warning: use '= default'
393 // CHECK-FIXES: NCRef &NCRef::operator=(NCRef &Other) = default;
394 
395 // Already defaulted.
396 struct IAD {
397   IAD(const IAD &Other) = default;
398   IAD &operator=(const IAD &Other) = default;
399 };
400 
401 struct OAD {
402   OAD(const OAD &Other);
403   OAD &operator=(const OAD &);
404 };
405 OAD::OAD(const OAD &Other) = default;
406 OAD &OAD::operator=(const OAD &Other) = default;
407 
408 // Deleted.
409 struct ID {
410   ID(const ID &Other) = delete;
411   ID &operator=(const ID &Other) = delete;
412 };
413 
414 // Non-reference parameter.
415 struct NRef {
416   NRef &operator=(NRef Other);
417   int Field1;
418 };
operator =(NRef Other)419 NRef &NRef::operator=(NRef Other) {
420   Field1 = Other.Field1;
421   return *this;
422 }
423 
424 // RValue reference parameter.
425 struct RVR {
RVRRVR426   RVR(RVR &&Other) {}
427   RVR &operator=(RVR &&);
428 };
operator =(RVR && Other)429 RVR &RVR::operator=(RVR &&Other) { return *this; }
430 
431 // Similar function.
432 struct SF {
433   SF &foo(const SF &);
434   int Field1;
435 };
foo(const SF & Other)436 SF &SF::foo(const SF &Other) {
437   Field1 = Other.Field1;
438   return *this;
439 }
440 
441 // No return.
442 struct NR {
443   NR &operator=(const NR &);
444 };
operator =(const NR & Other)445 NR &NR::operator=(const NR &Other) {}
446 
447 // Return misplaced.
448 struct RM {
449   RM &operator=(const RM &);
450   int Field;
451 };
operator =(const RM & Other)452 RM &RM::operator=(const RM &Other) {
453   return *this;
454   Field = Other.Field;
455 }
456 
457 // Wrong return value.
458 struct WRV {
459   WRV &operator=(WRV &);
460 };
operator =(WRV & Other)461 WRV &WRV::operator=(WRV &Other) {
462   return Other;
463 }
464 
465 // Wrong return type.
466 struct WRT : IL {
467   IL &operator=(const WRT &);
468 };
operator =(const WRT & Other)469 IL &WRT::operator=(const WRT &Other) {
470   return *this;
471 }
472 
473 // Wrong return type.
474 struct WRTConstRef {
operator =WRTConstRef475   const WRTConstRef &operator = (const WRTConstRef &) {
476     return *this;
477   }
478 };
479 
480 // Try-catch.
481 struct ITC {
ITCITC482   ITC(const ITC &Other)
483   try : Field(Other.Field) {
484   } catch (...) {
485   }
operator =ITC486   ITC &operator=(const ITC &Other) try {
487     Field = Other.Field;
488   } catch (...) {
489   }
490   int Field;
491 };
492 
493 struct OTC {
494   OTC(const OTC &);
495   OTC &operator=(const OTC &);
496   int Field;
497 };
OTC(const OTC & Other)498 OTC::OTC(const OTC &Other) try : Field(Other.Field) {
499 } catch (...) {
500 }
operator =(const OTC & Other)501 OTC &OTC::operator=(const OTC &Other) try {
502   Field = Other.Field;
503 } catch (...) {
504 }
505 
506 // FIXME: the check is not able to detect exception specification.
507 // noexcept(true).
508 struct NET {
509   // This is the default.
510   //NET(const NET &Other) noexcept {}
511   NET &operator=(const NET &Other) noexcept;
512 };
513 //NET &NET::operator=(const NET &Other) noexcept { return *this; }
514 
515 // noexcept(false).
516 struct NEF {
517   // This is the default.
518   //NEF(const NEF &Other) noexcept(false) {}
519   NEF &operator=(const NEF &Other) noexcept(false);
520 };
521 //NEF &NEF::operator=(const NEF &Other) noexcept(false) { return *this; }
522 
523 #define STRUCT_WITH_COPY_CONSTRUCT(_base, _type) \
524   struct _type {                                 \
525     _type(const _type &v) : value(v.value) {}    \
526     _base value;                                 \
527   };
528 
529 STRUCT_WITH_COPY_CONSTRUCT(unsigned char, Hex8CopyConstruct)
530 // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial copy constructor
531 // CHECK-MESSAGES: :[[@LINE-6]]:44: note:
532 
533 #define STRUCT_WITH_COPY_ASSIGN(_base, _type) \
534   struct _type {                              \
535     _type &operator=(const _type &rhs) {      \
536       value = rhs.value;                      \
537       return *this;                           \
538     }                                         \
539     _base value;                              \
540   };
541 
542 STRUCT_WITH_COPY_ASSIGN(unsigned char, Hex8CopyAssign)
543 // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial copy-assignment operator
544 // CHECK-MESSAGES: :[[@LINE-9]]:40: note:
545 
546 // Use of braces
547 struct UOB{
UOBUOB548   UOB(const UOB &Other):j{Other.j}{}
549   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' to define a trivial copy constructor [modernize-use-equals-default]
550   // CHECK-FIXES: UOB(const UOB &Other)= default;
551   int j;
552 };
553