187 lines · cpp
1// RUN: %check_clang_tidy %s misc-unconventional-assign-operator %t -- -- -fno-delayed-template-parsing2 3namespace std {4template <typename T>5struct remove_reference { typedef T type; };6template <typename T>7struct remove_reference<T &> { typedef T type; };8template <typename T>9struct remove_reference<T &&> { typedef T type; };10template <typename T>11typename remove_reference<T>::type &&move(T &&t);12}13 14 15struct Good {16 Good& operator=(const Good&);17 Good& operator=(Good&&);18 19 // Assign from other types is fine too.20 Good& operator=(int);21};22 23struct AlsoGood {24 // By value is also fine.25 AlsoGood& operator=(AlsoGood);26};27 28struct BadReturnType {29 void operator=(const BadReturnType&);30 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'BadReturnType&' [misc-unconventional-assign-operator]31 const BadReturnType& operator=(BadReturnType&&);32 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad33 void operator=(int);34 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad35};36 37struct BadReturnType2 {38 BadReturnType2&& operator=(const BadReturnType2&);39 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad40 int operator=(BadReturnType2&&);41 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad42};43 44struct BadArgument {45 BadArgument& operator=(BadArgument&);46 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should take 'BadArgument const&', 'BadArgument&&' or 'BadArgument'47 BadArgument& operator=(const BadArgument&&);48 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should take 'BadArgument const&', 'BadArgument&&' or 'BadArgument'49};50 51struct BadModifier {52 BadModifier& operator=(const BadModifier&) const;53 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'const'54};55 56struct Deleted {57 // We don't check the return value of deleted operators.58 void operator=(const Deleted&) = delete;59 void operator=(Deleted&&) = delete;60};61 62class Private {63 // We don't check the return value of private operators.64 // Pre-C++11 way of disabling assignment.65 void operator=(const Private &);66};67 68struct Virtual {69 virtual Virtual& operator=(const Virtual &);70 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'virtual'71};72 73class BadReturnStatement {74 int n;75 76public:77 BadReturnStatement& operator=(BadReturnStatement&& rhs) {78 n = std::move(rhs.n);79 return *&rhs;80// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always return '*this'81 }82 83 // Do not check if return type is different from '&BadReturnStatement'84 int operator=(int i) {85 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad86 n = i;87 return n;88 }89};90 91namespace pr31531 {92enum E { e };93// This declaration makes the 'return *this' below have an unresolved operator94// in the class template, but not in an instantiation.95E operator*(E, E);96 97template <typename>98struct UnresolvedOperator {99 UnresolvedOperator &operator=(const UnresolvedOperator &) { return *this; }100};101 102UnresolvedOperator<int> UnresolvedOperatorInt;103 104template <typename>105struct Template {106 Template &operator=(const Template &) { return this; }107 // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: operator=() should always return '*this'108};109 110Template<int> TemplateInt;111}112 113struct AssignmentCallAtReturn {114 AssignmentCallAtReturn &returnThis() {115 return *this;116 }117 AssignmentCallAtReturn &operator=(int rhs) {118 return *this;119 }120 AssignmentCallAtReturn &operator=(char rhs) {121 // Allow call to assignment from other type.122 return (*this = static_cast<int>(rhs));123 }124 AssignmentCallAtReturn &operator=(float rhs) {125 // Do not allow calls to other functions.126 return returnThis();127 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: operator=() should always return '*this'128 }129};130 131// Check that no false positives are issued when using type aliases.132struct TypeAlias {133 using Alias = TypeAlias;134 // This is correct and should not produce any warnings:135 Alias &operator=(const Alias &) { return *this; }136 137 using AliasRef = Alias &;138 // So is this (assignments from other types are fine):139 AliasRef operator=(int) { return *this; }140};141 142// Same check as above with typedef instead of using143struct TypeAliasTypedef {144 typedef TypeAliasTypedef Alias;145 Alias &operator=(const Alias &) { return *this; }146 147 typedef Alias &AliasRef;148 AliasRef operator=(int) { return *this; }149};150 151// Same check as above for a template class152template <typename T>153struct TemplateTypeAlias {154 using Alias1 = TemplateTypeAlias &;155 using Alias2 = TemplateTypeAlias const &;156 Alias1 operator=(Alias2) { return *this; }157 158 template <typename U>159 using Alias3 = TemplateTypeAlias<U>;160 Alias3<T> &operator=(int) { return *this; }161 162 // Using a different type parameter in the return type should give a warning163 Alias3<TypeAlias::Alias> &operator=(double) { return *this; }164 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'TemplateTypeAlias&' [misc-unconventional-assign-operator]165};166 167namespace gh143237 {168template<typename T>169struct TemplateAssignment {170 explicit TemplateAssignment(int) {171 }172 173 TemplateAssignment& operator=(int n) {174 // No warning175 return *this = TemplateAssignment(n);176 }177};178}179 180namespace GH153770 {181 struct A;182 struct A {183 A() = default;184 A& operator=(const A&) = default;185 };186} // namespace GH153770187