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 | |