| 1 | // RUN: %check_clang_tidy %s misc-unconventional-assign-operator %t -- -- -fno-delayed-template-parsing |
| 2 | |
| 3 | namespace std { |
| 4 | template <typename T> |
| 5 | struct remove_reference { typedef T type; }; |
| 6 | template <typename T> |
| 7 | struct remove_reference<T &> { typedef T type; }; |
| 8 | template <typename T> |
| 9 | struct remove_reference<T &&> { typedef T type; }; |
| 10 | template <typename T> |
| 11 | typename remove_reference<T>::type &&move(T &&t); |
| 12 | } |
| 13 | |
| 14 | |
| 15 | struct 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 | |
| 23 | struct AlsoGood { |
| 24 | // By value is also fine. |
| 25 | AlsoGood& operator=(AlsoGood); |
| 26 | }; |
| 27 | |
| 28 | struct 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 'Bad |
| 33 | void operator=(int); |
| 34 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad |
| 35 | }; |
| 36 | |
| 37 | struct BadReturnType2 { |
| 38 | BadReturnType2&& operator=(const BadReturnType2&); |
| 39 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad |
| 40 | int operator=(BadReturnType2&&); |
| 41 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad |
| 42 | }; |
| 43 | |
| 44 | struct 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 | |
| 51 | struct BadModifier { |
| 52 | BadModifier& operator=(const BadModifier&) const; |
| 53 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'const' |
| 54 | }; |
| 55 | |
| 56 | struct 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 | |
| 62 | class 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 | |
| 68 | struct Virtual { |
| 69 | virtual Virtual& operator=(const Virtual &); |
| 70 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should not be marked 'virtual' |
| 71 | }; |
| 72 | |
| 73 | class BadReturnStatement { |
| 74 | int n; |
| 75 | |
| 76 | public: |
| 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 'Bad |
| 86 | n = i; |
| 87 | return n; |
| 88 | } |
| 89 | }; |
| 90 | |
| 91 | namespace pr31531 { |
| 92 | enum E { e }; |
| 93 | // This declaration makes the 'return *this' below have an unresolved operator |
| 94 | // in the class template, but not in an instantiation. |
| 95 | E operator*(E, E); |
| 96 | |
| 97 | template <typename> |
| 98 | struct UnresolvedOperator { |
| 99 | UnresolvedOperator &operator=(const UnresolvedOperator &) { return *this; } |
| 100 | }; |
| 101 | |
| 102 | UnresolvedOperator<int> UnresolvedOperatorInt; |
| 103 | |
| 104 | template <typename> |
| 105 | struct Template { |
| 106 | Template &operator=(const Template &) { return this; } |
| 107 | // CHECK-MESSAGES: :[[@LINE-1]]:43: warning: operator=() should always return '*this' |
| 108 | }; |
| 109 | |
| 110 | Template<int> TemplateInt; |
| 111 | } |
| 112 | |
| 113 | struct 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. |
| 132 | struct 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 using |
| 143 | struct 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 class |
| 152 | template <typename T> |
| 153 | struct 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 warning |
| 163 | Alias3<TypeAlias::Alias> &operator=(double) { return *this; } |
| 164 | // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'TemplateTypeAlias&' [misc-unconventional-assign-operator] |
| 165 | }; |
| 166 | |