1// RUN: %check_clang_tidy %s misc-unconventional-assign-operator %t -- -- -fno-delayed-template-parsing
2
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 'Bad
33 void operator=(int);
34 // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'Bad
35};
36
37struct 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
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 'Bad
86 n = i;
87 return n;
88 }
89};
90
91namespace pr31531 {
92enum E { e };
93// This declaration makes the 'return *this' below have an unresolved operator
94// 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 using
143struct 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
152template <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 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

source code of clang-tools-extra/test/clang-tidy/checkers/misc/unconventional-assign-operator.cpp