// RUN: %check_clang_tidy %s modernize-use-equals-default %t -- \ // RUN: -config="{CheckOptions: [{key: modernize-use-equals-default.IgnoreMacros, value: 0}]}" \ // RUN: -- -std=c++11 -fno-delayed-template-parsing -fexceptions // Out of line definition. struct OL { OL(const OL &); OL &operator=(const OL &); int Field; }; OL::OL(const OL &Other) : Field(Other.Field) {} // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use '= default' to define a trivial copy constructor [modernize-use-equals-default] // CHECK-FIXES: OL::OL(const OL &Other) = default; OL &OL::operator=(const OL &Other) { Field = Other.Field; return *this; } // CHECK-MESSAGES: :[[@LINE-4]]:9: warning: use '= default' to define a trivial copy-assignment operator [modernize-use-equals-default] // CHECK-FIXES: OL &OL::operator=(const OL &Other) = default; // Inline. struct IL { IL(const IL &Other) : Field(Other.Field) {} // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' // CHECK-FIXES: IL(const IL &Other) = default; IL &operator=(const IL &Other) { Field = Other.Field; return *this; } // CHECK-MESSAGES: :[[@LINE-4]]:7: warning: use '= default' // CHECK-FIXES: IL &operator=(const IL &Other) = default; int Field; }; // Wrong type. struct WT { WT(const IL &Other) {} WT &operator=(const IL &); }; WT &WT::operator=(const IL &Other) { return *this; } // Qualifiers. struct Qual { Qual(const Qual &Other) : Field(Other.Field), Volatile(Other.Volatile), Mutable(Other.Mutable), Reference(Other.Reference), Const(Other.Const) {} // CHECK-MESSAGES: :[[@LINE-3]]:3: warning: use '= default' // CHECK-FIXES: Qual(const Qual &Other) // CHECK-FIXES: = default; int Field; volatile char Volatile; mutable bool Mutable; const OL &Reference; // This makes this class non-assignable. const IL Const; // This also makes this class non-assignable. static int Static; }; // Wrong init arguments. struct WI { WI(const WI &Other) : Field1(Other.Field1), Field2(Other.Field1) {} WI &operator=(const WI &); int Field1, Field2; }; WI &WI::operator=(const WI &Other) { Field1 = Other.Field1; Field2 = Other.Field1; return *this; } // Missing field. struct MF { MF(const MF &Other) : Field1(Other.Field1), Field2(Other.Field2) {} MF &operator=(const MF &); int Field1, Field2, Field3; }; MF &MF::operator=(const MF &Other) { Field1 = Other.Field1; Field2 = Other.Field2; return *this; } struct Comments { Comments(const Comments &Other) /* don't delete */ : /* this comment */ Field(Other.Field) {} // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default' // CHECK-FIXES: /* don't delete */ = default; int Field; }; struct MoreComments { MoreComments(const MoreComments &Other) /* this comment is OK */ : Field(Other.Field) {} // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default' // CHECK-FIXES: MoreComments(const MoreComments &Other) /* this comment is OK */ // CHECK-FIXES-NEXT: = default; int Field; }; struct ColonInComment { ColonInComment(const ColonInComment &Other) /* : */ : Field(Other.Field) {} // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' // CHECK-FIXES: ColonInComment(const ColonInComment &Other) /* : */ = default; int Field; }; // No members or bases (in particular, no colon). struct Empty { Empty(const Empty &Other) {} // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' // CHECK-FIXES: Empty(const Empty &Other) = default; Empty &operator=(const Empty &); }; Empty &Empty::operator=(const Empty &Other) { return *this; } // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use '= default' // CHECK-FIXES: Empty &Empty::operator=(const Empty &Other) = default; // Bit fields. struct BF { BF() = default; BF(const BF &Other) : Field1(Other.Field1), Field2(Other.Field2), Field3(Other.Field3), Field4(Other.Field4) {} // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default' // CHECK-FIXES: BF(const BF &Other) {{$}} // CHECK-FIXES: = default; BF &operator=(const BF &); unsigned Field1 : 3; int : 7; char Field2 : 6; int : 0; int Field3 : 24; unsigned char Field4; }; BF &BF::operator=(const BF &Other) { Field1 = Other.Field1; Field2 = Other.Field2; Field3 = Other.Field3; Field4 = Other.Field4; return *this; } // CHECK-MESSAGES: :[[@LINE-7]]:9: warning: use '= default' // CHECK-FIXES: BF &BF::operator=(const BF &Other) = default; // Base classes. struct BC : IL, OL, BF { BC(const BC &Other) : IL(Other), OL(Other), BF(Other) {} // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' // CHECK-FIXES: BC(const BC &Other) = default; BC &operator=(const BC &Other); }; BC &BC::operator=(const BC &Other) { IL::operator=(Other); OL::operator=(Other); BF::operator=(Other); return *this; } // CHECK-MESSAGES: :[[@LINE-6]]:9: warning: use '= default' // CHECK-FIXES: BC &BC::operator=(const BC &Other) = default; // Base classes with member. struct BCWM : IL, OL { BCWM(const BCWM &Other) : IL(Other), OL(Other), Bf(Other.Bf) {} // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' // CHECK-FIXES: BCWM(const BCWM &Other) = default; BCWM &operator=(const BCWM &); BF Bf; }; BCWM &BCWM::operator=(const BCWM &Other) { IL::operator=(Other); OL::operator=(Other); Bf = Other.Bf; return *this; } // CHECK-MESSAGES: :[[@LINE-6]]:13: warning: use '= default' // CHECK-FIXES: BCWM &BCWM::operator=(const BCWM &Other) = default; // Missing base class. struct MBC : IL, OL, BF { MBC(const MBC &Other) : IL(Other), OL(Other) {} MBC &operator=(const MBC &); }; MBC &MBC::operator=(const MBC &Other) { IL::operator=(Other); OL::operator=(Other); return *this; } // Base classes, incorrect parameter. struct BCIP : BCWM, BF { BCIP(const BCIP &Other) : BCWM(Other), BF(Other.Bf) {} BCIP &operator=(const BCIP &); }; BCIP &BCIP::operator=(const BCIP &Other) { BCWM::operator=(Other); BF::operator=(Other.Bf); return *this; } // Virtual base classes. struct VA : virtual OL {}; struct VB : virtual OL {}; struct VBC : VA, VB, virtual OL { // OL is the first thing that is going to be initialized, despite the fact // that it is the last in the list of bases, because it is virtual and there // is a virtual OL at the beginning of VA (which is the same). VBC(const VBC &Other) : OL(Other), VA(Other), VB(Other) {} // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' // CHECK-FIXES: VBC(const VBC &Other) = default; VBC &operator=(const VBC &Other); }; VBC &VBC::operator=(const VBC &Other) { OL::operator=(Other); VA::operator=(Other); VB::operator=(Other); return *this; } // CHECK-MESSAGES: :[[@LINE-6]]:11: warning: use '= default' // CHECK-FIXES: VBC &VBC::operator=(const VBC &Other) = default; // Indirect base. struct IB : VBC { IB(const IB &Other) : OL(Other), VBC(Other) {} IB &operator=(const IB &); }; IB &IB::operator=(const IB &Other) { OL::operator=(Other); VBC::operator=(Other); return *this; } // Class template. template struct Template { Template() = default; Template(const Template &Other) : Field(Other.Field) {} Template &operator=(const Template &Other); void foo(const T &t); int Field; }; template Template &Template::operator=(const Template &Other) { Field = Other.Field; return *this; } Template T1; // Dependent types. template struct DT1 { DT1() = default; DT1(const DT1 &Other) : Field(Other.Field) {} DT1 &operator=(const DT1 &); T Field; }; template DT1 &DT1::operator=(const DT1 &Other) { Field = Other.Field; return *this; } DT1 Dt1; template struct DT2 { DT2() = default; DT2(const DT2 &Other) : Field(Other.Field), Dependent(Other.Dependent) {} DT2 &operator=(const DT2 &); T Field; typename T::TT Dependent; }; template DT2 &DT2::operator=(const DT2 &Other) { Field = Other.Field; Dependent = Other.Dependent; return *this; } struct T { typedef int TT; }; DT2 Dt2; // Default arguments. struct DA { DA(int Int); DA(const DA &Other = DA(0)) : Field1(Other.Field1), Field2(Other.Field2) {} DA &operator=(const DA &); int Field1; char Field2; }; // Overloaded operator= cannot have a default argument. DA &DA::operator=(const DA &Other) { Field1 = Other.Field1; Field2 = Other.Field2; return *this; } // CHECK-MESSAGES: :[[@LINE-5]]:9: warning: use '= default' // CHECK-FIXES: DA &DA::operator=(const DA &Other) = default; struct DA2 { // Can be used as copy-constructor but cannot be explicitly defaulted. DA2(const DA &Other, int Def = 0) {} }; // Default initialization. struct DI { DI(const DI &Other) : Field1(Other.Field1), Field2(Other.Field2) {} int Field1; int Field2 = 0; int Fiedl3; }; // Statement inside body. void foo(); struct SIB { SIB(const SIB &Other) : Field(Other.Field) { foo(); } SIB &operator=(const SIB &); int Field; }; SIB &SIB::operator=(const SIB &Other) { Field = Other.Field; foo(); return *this; } // Comment inside body. struct CIB { CIB(const CIB &Other) : Field(Other.Field) { /* Don't erase this */ } // CHECK-MESSAGES: :[[@LINE-2]]:3: warning: use '= default' CIB &operator=(const CIB &); int Field; }; CIB &CIB::operator=(const CIB &Other) { Field = Other.Field; // FIXME: don't erase this comment. return *this; } // CHECK-MESSAGES: :[[@LINE-5]]:11: warning: use '= default' // CHECK-FIXES: CIB &CIB::operator=(const CIB &Other) = default; // Take non-const reference as argument. struct NCRef { NCRef(NCRef &Other) : Field1(Other.Field1), Field2(Other.Field2) {} // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' // CHECK-FIXES: NCRef(NCRef &Other) = default; NCRef &operator=(NCRef &); int Field1, Field2; }; NCRef &NCRef::operator=(NCRef &Other) { Field1 = Other.Field1; Field2 = Other.Field2; return *this; } // CHECK-MESSAGES: :[[@LINE-5]]:15: warning: use '= default' // CHECK-FIXES: NCRef &NCRef::operator=(NCRef &Other) = default; // Already defaulted. struct IAD { IAD(const IAD &Other) = default; IAD &operator=(const IAD &Other) = default; }; struct OAD { OAD(const OAD &Other); OAD &operator=(const OAD &); }; OAD::OAD(const OAD &Other) = default; OAD &OAD::operator=(const OAD &Other) = default; // Deleted. struct ID { ID(const ID &Other) = delete; ID &operator=(const ID &Other) = delete; }; // Non-reference parameter. struct NRef { NRef &operator=(NRef Other); int Field1; }; NRef &NRef::operator=(NRef Other) { Field1 = Other.Field1; return *this; } // RValue reference parameter. struct RVR { RVR(RVR &&Other) {} RVR &operator=(RVR &&); }; RVR &RVR::operator=(RVR &&Other) { return *this; } // Similar function. struct SF { SF &foo(const SF &); int Field1; }; SF &SF::foo(const SF &Other) { Field1 = Other.Field1; return *this; } // No return. struct NR { NR &operator=(const NR &); }; NR &NR::operator=(const NR &Other) {} // Return misplaced. struct RM { RM &operator=(const RM &); int Field; }; RM &RM::operator=(const RM &Other) { return *this; Field = Other.Field; } // Wrong return value. struct WRV { WRV &operator=(WRV &); }; WRV &WRV::operator=(WRV &Other) { return Other; } // Wrong return type. struct WRT : IL { IL &operator=(const WRT &); }; IL &WRT::operator=(const WRT &Other) { return *this; } // Try-catch. struct ITC { ITC(const ITC &Other) try : Field(Other.Field) { } catch (...) { } ITC &operator=(const ITC &Other) try { Field = Other.Field; } catch (...) { } int Field; }; struct OTC { OTC(const OTC &); OTC &operator=(const OTC &); int Field; }; OTC::OTC(const OTC &Other) try : Field(Other.Field) { } catch (...) { } OTC &OTC::operator=(const OTC &Other) try { Field = Other.Field; } catch (...) { } // FIXME: the check is not able to detect exception specification. // noexcept(true). struct NET { // This is the default. //NET(const NET &Other) noexcept {} NET &operator=(const NET &Other) noexcept; }; //NET &NET::operator=(const NET &Other) noexcept { return *this; } // noexcept(false). struct NEF { // This is the default. //NEF(const NEF &Other) noexcept(false) {} NEF &operator=(const NEF &Other) noexcept(false); }; //NEF &NEF::operator=(const NEF &Other) noexcept(false) { return *this; } #define STRUCT_WITH_COPY_CONSTRUCT(_base, _type) \ struct _type { \ _type(const _type &v) : value(v.value) {} \ _base value; \ }; STRUCT_WITH_COPY_CONSTRUCT(unsigned char, Hex8CopyConstruct) // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial copy constructor // CHECK-MESSAGES: :[[@LINE-6]]:44: note: #define STRUCT_WITH_COPY_ASSIGN(_base, _type) \ struct _type { \ _type &operator=(const _type &rhs) { \ value = rhs.value; \ return *this; \ } \ _base value; \ }; STRUCT_WITH_COPY_ASSIGN(unsigned char, Hex8CopyAssign) // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use '= default' to define a trivial copy-assignment operator // CHECK-MESSAGES: :[[@LINE-9]]:40: note: // Use of braces struct UOB{ UOB(const UOB &Other):j{Other.j}{} // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' to define a trivial copy constructor [modernize-use-equals-default] // CHECK-FIXES: UOB(const UOB &Other)= default; int j; };