| // 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 <class T> |
| struct Template { |
| Template() = default; |
| Template(const Template &Other) : Field(Other.Field) {} |
| Template &operator=(const Template &Other); |
| void foo(const T &t); |
| int Field; |
| }; |
| template <class T> |
| Template<T> &Template<T>::operator=(const Template<T> &Other) { |
| Field = Other.Field; |
| return *this; |
| } |
| Template<int> T1; |
| |
| // Dependent types. |
| template <class T> |
| struct DT1 { |
| DT1() = default; |
| DT1(const DT1 &Other) : Field(Other.Field) {} |
| DT1 &operator=(const DT1 &); |
| T Field; |
| }; |
| template <class T> |
| DT1<T> &DT1<T>::operator=(const DT1<T> &Other) { |
| Field = Other.Field; |
| return *this; |
| } |
| DT1<int> Dt1; |
| |
| template <class T> |
| 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 <class T> |
| DT2<T> &DT2<T>::operator=(const DT2<T> &Other) { |
| Field = Other.Field; |
| Dependent = Other.Dependent; |
| return *this; |
| } |
| struct T { |
| typedef int TT; |
| }; |
| DT2<T> 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; |
| }; |