1 // RUN: %check_clang_tidy %s readability-make-member-function-const %t
2
3 struct Str {
4 void const_method() const;
5 void non_const_method();
6 };
7
8 namespace Diagnose {
9 struct A;
10
11 void free_const_use(const A *);
12 void free_const_use(const A &);
13
14 struct A {
15 int M;
16 const int ConstM;
17 struct {
18 int M;
19 } Struct;
20 Str S;
21 Str &Sref;
22
23 void already_const() const;
24
read_fieldDiagnose::A25 int read_field() {
26 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_field' can be made const
27 // CHECK-FIXES: {{^}} int read_field() const {
28 return M;
29 }
30
read_struct_fieldDiagnose::A31 int read_struct_field() {
32 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_struct_field' can be made const
33 // CHECK-FIXES: {{^}} int read_struct_field() const {
34 return Struct.M;
35 }
36
read_const_fieldDiagnose::A37 int read_const_field() {
38 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_const_field' can be made const
39 // CHECK-FIXES: {{^}} int read_const_field() const {
40 return ConstM;
41 }
42
read_fields_in_parenthesesDiagnose::A43 int read_fields_in_parentheses() {
44 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'read_fields_in_parentheses' can be made const
45 // CHECK-FIXES: {{^}} int read_fields_in_parentheses() const {
46 return (this)->M + (((((Struct.M))))) + ((this->ConstM));
47 }
48
call_const_memberDiagnose::A49 void call_const_member() {
50 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can be made const
51 // CHECK-FIXES: {{^}} void call_const_member() const {
52 already_const();
53 }
54
call_const_member_on_public_fieldDiagnose::A55 void call_const_member_on_public_field() {
56 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field' can be made const
57 // CHECK-FIXES: {{^}} void call_const_member_on_public_field() const {
58 S.const_method();
59 }
60
call_const_member_on_public_field_refDiagnose::A61 void call_const_member_on_public_field_ref() {
62 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field_ref' can be made const
63 // CHECK-FIXES: {{^}} void call_const_member_on_public_field_ref() const {
64 Sref.const_method();
65 }
66
return_public_field_refDiagnose::A67 const Str &return_public_field_ref() {
68 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: method 'return_public_field_ref' can be made const
69 // CHECK-FIXES: {{^}} const Str &return_public_field_ref() const {
70 return S;
71 }
72
return_this_constDiagnose::A73 const A *return_this_const() {
74 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const' can be made const
75 // CHECK-FIXES: {{^}} const A *return_this_const() const {
76 return this;
77 }
78
return_this_const_refDiagnose::A79 const A &return_this_const_ref() {
80 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const_ref' can be made const
81 // CHECK-FIXES: {{^}} const A &return_this_const_ref() const {
82 return *this;
83 }
84
const_useDiagnose::A85 void const_use() {
86 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use' can be made const
87 // CHECK-FIXES: {{^}} void const_use() const {
88 free_const_use(this);
89 }
90
const_use_refDiagnose::A91 void const_use_ref() {
92 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use_ref' can be made const
93 // CHECK-FIXES: {{^}} void const_use_ref() const {
94 free_const_use(*this);
95 }
96
trailingReturnDiagnose::A97 auto trailingReturn() -> int {
98 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'trailingReturn' can be made const
99 // CHECK-FIXES: {{^}} auto trailingReturn() const -> int {
100 return M;
101 }
102
volatileFunctionDiagnose::A103 int volatileFunction() volatile {
104 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'volatileFunction' can be made const
105 // CHECK-FIXES: {{^}} int volatileFunction() const volatile {
106 return M;
107 }
108
restrictFunctionDiagnose::A109 int restrictFunction() __restrict {
110 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'restrictFunction' can be made const
111 // CHECK-FIXES: {{^}} int restrictFunction() const __restrict {
112 return M;
113 }
114
refFunctionDiagnose::A115 int refFunction() & {
116 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'refFunction' can be made const
117 // CHECK-FIXES: {{^}} int refFunction() const & {
118 return M;
119 }
120
121 void out_of_line_call_const();
122 // CHECK-FIXES: {{^}} void out_of_line_call_const() const;
123 };
124
out_of_line_call_const()125 void A::out_of_line_call_const() {
126 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'out_of_line_call_const' can be made const
127 // CHECK-FIXES: {{^}}void A::out_of_line_call_const() const {
128 already_const();
129 }
130 } // namespace Diagnose
131
132 namespace Keep {
133 struct Keep;
134 void free_non_const_use(Keep *);
135 void free_non_const_use(Keep &);
136
137 struct Keep {
138 private:
139 void private_const_method() const;
140 Str PrivateS;
141 Str *Sptr;
142 Str &Sref;
143
144 public:
145 int M;
146 Str S;
147
keepTrivialKeep::Keep148 void keepTrivial() {}
149
150 // See readability-convert-member-functions-to-static instead.
keepStaticKeep::Keep151 void keepStatic() { int I = 0; }
152
153 const int *keepConstCast() const;
keepConstCastKeep::Keep154 int *keepConstCast() { // Needs to stay non-const.
155 return const_cast<int *>(static_cast<const Keep *>(this)->keepConstCast());
156 }
157
non_const_useKeep::Keep158 void non_const_use() { free_non_const_use(this); }
non_const_use_refKeep::Keep159 void non_const_use_ref() { free_non_const_use(*this); }
160
return_thisKeep::Keep161 Keep *return_this() {
162 return this;
163 }
164
return_this_refKeep::Keep165 Keep &return_this_ref() {
166 return *this;
167 }
168
escape_thisKeep::Keep169 void escape_this() {
170 Keep *Escaped = this;
171 }
172
call_private_const_methodKeep::Keep173 void call_private_const_method() {
174 private_const_method();
175 }
176
keepConstKeep::Keep177 int keepConst() const { return M; }
178
keepVirtualKeep::Keep179 virtual int keepVirtual() { return M; }
180
writeFieldKeep::Keep181 void writeField() {
182 M = 1;
183 }
184
callNonConstMemberKeep::Keep185 void callNonConstMember() { writeField(); }
186
call_non_const_member_on_fieldKeep::Keep187 void call_non_const_member_on_field() { S.non_const_method(); }
188
call_const_member_on_private_fieldKeep::Keep189 void call_const_member_on_private_field() {
190 // Technically, this method could be const-qualified,
191 // but it might not be logically const.
192 PrivateS.const_method();
193 }
194
return_private_field_refKeep::Keep195 const Str &return_private_field_ref() {
196 // Technically, this method could be const-qualified,
197 // but it might not be logically const.
198 return PrivateS;
199 }
200
call_non_const_member_on_pointeeKeep::Keep201 void call_non_const_member_on_pointee() {
202 Sptr->non_const_method();
203 }
204
call_const_member_on_pointeeKeep::Keep205 void call_const_member_on_pointee() {
206 // Technically, this method could be const-qualified,
207 // but it might not be logically const.
208 Sptr->const_method();
209 }
210
return_pointerKeep::Keep211 Str *return_pointer() {
212 // Technically, this method could be const-qualified,
213 // but it might not be logically const.
214 return Sptr;
215 }
216
return_const_pointerKeep::Keep217 const Str *return_const_pointer() {
218 // Technically, this method could be const-qualified,
219 // but it might not be logically const.
220 return Sptr;
221 }
222
call_non_const_member_on_refKeep::Keep223 void call_non_const_member_on_ref() {
224 Sref.non_const_method();
225 }
226
escaped_private_fieldKeep::Keep227 void escaped_private_field() {
228 const auto &Escaped = Sref;
229 }
230
return_field_refKeep::Keep231 Str &return_field_ref() {
232 // Technically, this method could be const-qualified,
233 // but it might not be logically const.
234 return Sref;
235 }
236
return_field_const_refKeep::Keep237 const Str &return_field_const_ref() {
238 // Technically, this method could be const-qualified,
239 // but it might not be logically const.
240 return Sref;
241 }
242 };
243
244 struct KeepVirtualDerived : public Keep {
keepVirtualKeep::KeepVirtualDerived245 int keepVirtual() { return M; }
246 };
247
KeepLambdas()248 void KeepLambdas() {
249 auto F = +[]() { return 0; };
250 auto F2 = []() { return 0; };
251 }
252
253 template <class Base>
254 struct KeepWithDependentBase : public Base {
255 int M;
256 // We cannot make this method const because it might need to override
257 // a function from Base.
const_fKeep::KeepWithDependentBase258 int const_f() { return M; }
259 };
260
261 template <class T>
262 struct KeepClassTemplate {
263 int M;
264 // We cannot make this method const because a specialization
265 // might use *this differently.
const_fKeep::KeepClassTemplate266 int const_f() { return M; }
267 };
268
269 struct KeepMemberFunctionTemplate {
270 int M;
271 // We cannot make this method const because a specialization
272 // might use *this differently.
273 template <class T>
const_fKeep::KeepMemberFunctionTemplate274 int const_f() { return M; }
275 };
276
instantiate()277 void instantiate() {
278 struct S {};
279 KeepWithDependentBase<S> I1;
280 I1.const_f();
281
282 KeepClassTemplate<int> I2;
283 I2.const_f();
284
285 KeepMemberFunctionTemplate I3;
286 I3.const_f<int>();
287 }
288
289 struct NoFixitInMacro {
290 int M;
291
292 #define FUN const_use_macro()
293 int FUN {
294 return M;
295 }
296
297 #define T(FunctionName, Keyword) \
298 int FunctionName() Keyword { return M; }
299 #define EMPTY
300 T(A, EMPTY)
301 T(B, const)
302
303 #define T2(FunctionName) \
304 int FunctionName() { return M; }
305 T2(A2)
306 };
307
308 // Real-world code, see clang::ObjCInterfaceDecl.
309 class DataPattern {
310 int &data() const;
311
312 public:
get() const313 const int &get() const {
314 return const_cast<DataPattern *>(this)->get();
315 }
316
317 // This member function must stay non-const, even though
318 // it only calls other private const member functions.
get()319 int &get() {
320 return data();
321 }
322
set()323 void set() {
324 data() = 42;
325 }
326 };
327
328 struct MemberFunctionPointer {
call_non_constKeep::MemberFunctionPointer329 void call_non_const(void (MemberFunctionPointer::*FP)()) {
330 (this->*FP)();
331 }
332
call_constKeep::MemberFunctionPointer333 void call_const(void (MemberFunctionPointer::*FP)() const) {
334 (this->*FP)();
335 }
336 };
337
338 } // namespace Keep
339