xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/misc/unconventional-assign-operator.cpp (revision fda777849b0088ba83e28683c53c5c8321ef2558)
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:
operator =(BadReturnStatement && rhs)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'
operator =(int i)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 {
operator =pr31531::UnresolvedOperator99   UnresolvedOperator &operator=(const UnresolvedOperator &) { return *this; }
100 };
101 
102 UnresolvedOperator<int> UnresolvedOperatorInt;
103 
104 template <typename>
105 struct Template {
operator =pr31531::Template106   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 {
returnThisAssignmentCallAtReturn114   AssignmentCallAtReturn &returnThis() {
115     return *this;
116   }
operator =AssignmentCallAtReturn117   AssignmentCallAtReturn &operator=(int rhs) {
118     return *this;
119   }
operator =AssignmentCallAtReturn120   AssignmentCallAtReturn &operator=(char rhs) {
121     // Allow call to assignment from other type.
122     return (*this = static_cast<int>(rhs));
123   }
operator =AssignmentCallAtReturn124   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:
operator =TypeAlias135   Alias &operator=(const Alias &) { return *this; }
136 
137   using AliasRef = Alias &;
138   // So is this (assignments from other types are fine):
operator =TypeAlias139   AliasRef operator=(int) { return *this; }
140 };
141 
142 // Same check as above with typedef instead of using
143 struct TypeAliasTypedef {
144   typedef TypeAliasTypedef Alias;
operator =TypeAliasTypedef145   Alias &operator=(const Alias &) { return *this; }
146 
147   typedef Alias &AliasRef;
operator =TypeAliasTypedef148   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 &;
operator =TemplateTypeAlias156   Alias1 operator=(Alias2) { return *this; }
157 
158   template <typename U>
159   using Alias3 = TemplateTypeAlias<U>;
operator =TemplateTypeAlias160   Alias3<T> &operator=(int) { return *this; }
161 
162   // Using a different type parameter in the return type should give a warning
operator =TemplateTypeAlias163   Alias3<TypeAlias::Alias> &operator=(double) { return *this; }
164   // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: operator=() should return 'TemplateTypeAlias&' [misc-unconventional-assign-operator]
165 };
166