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
call_const_memberDiagnose::A43 void call_const_member() {
44 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member' can be made const
45 // CHECK-FIXES: {{^}} void call_const_member() const {
46 already_const();
47 }
48
call_const_member_on_public_fieldDiagnose::A49 void call_const_member_on_public_field() {
50 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field' can be made const
51 // CHECK-FIXES: {{^}} void call_const_member_on_public_field() const {
52 S.const_method();
53 }
54
call_const_member_on_public_field_refDiagnose::A55 void call_const_member_on_public_field_ref() {
56 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'call_const_member_on_public_field_ref' can be made const
57 // CHECK-FIXES: {{^}} void call_const_member_on_public_field_ref() const {
58 Sref.const_method();
59 }
60
return_public_field_refDiagnose::A61 const Str &return_public_field_ref() {
62 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: method 'return_public_field_ref' can be made const
63 // CHECK-FIXES: {{^}} const Str &return_public_field_ref() const {
64 return S;
65 }
66
return_this_constDiagnose::A67 const A *return_this_const() {
68 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const' can be made const
69 // CHECK-FIXES: {{^}} const A *return_this_const() const {
70 return this;
71 }
72
return_this_const_refDiagnose::A73 const A &return_this_const_ref() {
74 // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: method 'return_this_const_ref' can be made const
75 // CHECK-FIXES: {{^}} const A &return_this_const_ref() const {
76 return *this;
77 }
78
const_useDiagnose::A79 void const_use() {
80 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use' can be made const
81 // CHECK-FIXES: {{^}} void const_use() const {
82 free_const_use(this);
83 }
84
const_use_refDiagnose::A85 void const_use_ref() {
86 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'const_use_ref' can be made const
87 // CHECK-FIXES: {{^}} void const_use_ref() const {
88 free_const_use(*this);
89 }
90
trailingReturnDiagnose::A91 auto trailingReturn() -> int {
92 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: method 'trailingReturn' can be made const
93 // CHECK-FIXES: {{^}} auto trailingReturn() const -> int {
94 return M;
95 }
96
volatileFunctionDiagnose::A97 int volatileFunction() volatile {
98 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'volatileFunction' can be made const
99 // CHECK-FIXES: {{^}} int volatileFunction() const volatile {
100 return M;
101 }
102
restrictFunctionDiagnose::A103 int restrictFunction() __restrict {
104 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'restrictFunction' can be made const
105 // CHECK-FIXES: {{^}} int restrictFunction() const __restrict {
106 return M;
107 }
108
refFunctionDiagnose::A109 int refFunction() & {
110 // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: method 'refFunction' can be made const
111 // CHECK-FIXES: {{^}} int refFunction() const & {
112 return M;
113 }
114
115 void out_of_line_call_const();
116 // CHECK-FIXES: {{^}} void out_of_line_call_const() const;
117 };
118
out_of_line_call_const()119 void A::out_of_line_call_const() {
120 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: method 'out_of_line_call_const' can be made const
121 // CHECK-FIXES: {{^}}void A::out_of_line_call_const() const {
122 already_const();
123 }
124 } // namespace Diagnose
125
126 namespace Keep {
127 struct Keep;
128 void free_non_const_use(Keep *);
129 void free_non_const_use(Keep &);
130
131 struct Keep {
132 private:
133 void private_const_method() const;
134 Str PrivateS;
135 Str *Sptr;
136 Str &Sref;
137
138 public:
139 int M;
140 Str S;
141
keepTrivialKeep::Keep142 void keepTrivial() {}
143
144 // See readability-convert-member-functions-to-static instead.
keepStaticKeep::Keep145 void keepStatic() { int I = 0; }
146
147 const int *keepConstCast() const;
keepConstCastKeep::Keep148 int *keepConstCast() { // Needs to stay non-const.
149 return const_cast<int *>(static_cast<const Keep *>(this)->keepConstCast());
150 }
151
non_const_useKeep::Keep152 void non_const_use() { free_non_const_use(this); }
non_const_use_refKeep::Keep153 void non_const_use_ref() { free_non_const_use(*this); }
154
return_thisKeep::Keep155 Keep *return_this() {
156 return this;
157 }
158
return_this_refKeep::Keep159 Keep &return_this_ref() {
160 return *this;
161 }
162
escape_thisKeep::Keep163 void escape_this() {
164 Keep *Escaped = this;
165 }
166
call_private_const_methodKeep::Keep167 void call_private_const_method() {
168 private_const_method();
169 }
170
keepConstKeep::Keep171 int keepConst() const { return M; }
172
keepVirtualKeep::Keep173 virtual int keepVirtual() { return M; }
174
writeFieldKeep::Keep175 void writeField() {
176 M = 1;
177 }
178
callNonConstMemberKeep::Keep179 void callNonConstMember() { writeField(); }
180
call_non_const_member_on_fieldKeep::Keep181 void call_non_const_member_on_field() { S.non_const_method(); }
182
call_const_member_on_private_fieldKeep::Keep183 void call_const_member_on_private_field() {
184 // Technically, this method could be const-qualified,
185 // but it might not be logically const.
186 PrivateS.const_method();
187 }
188
return_private_field_refKeep::Keep189 const Str &return_private_field_ref() {
190 // Technically, this method could be const-qualified,
191 // but it might not be logically const.
192 return PrivateS;
193 }
194
call_non_const_member_on_pointeeKeep::Keep195 void call_non_const_member_on_pointee() {
196 Sptr->non_const_method();
197 }
198
call_const_member_on_pointeeKeep::Keep199 void call_const_member_on_pointee() {
200 // Technically, this method could be const-qualified,
201 // but it might not be logically const.
202 Sptr->const_method();
203 }
204
return_pointerKeep::Keep205 Str *return_pointer() {
206 // Technically, this method could be const-qualified,
207 // but it might not be logically const.
208 return Sptr;
209 }
210
return_const_pointerKeep::Keep211 const Str *return_const_pointer() {
212 // Technically, this method could be const-qualified,
213 // but it might not be logically const.
214 return Sptr;
215 }
216
call_non_const_member_on_refKeep::Keep217 void call_non_const_member_on_ref() {
218 Sref.non_const_method();
219 }
220
escaped_private_fieldKeep::Keep221 void escaped_private_field() {
222 const auto &Escaped = Sref;
223 }
224
return_field_refKeep::Keep225 Str &return_field_ref() {
226 // Technically, this method could be const-qualified,
227 // but it might not be logically const.
228 return Sref;
229 }
230
return_field_const_refKeep::Keep231 const Str &return_field_const_ref() {
232 // Technically, this method could be const-qualified,
233 // but it might not be logically const.
234 return Sref;
235 }
236 };
237
238 struct KeepVirtualDerived : public Keep {
keepVirtualKeep::KeepVirtualDerived239 int keepVirtual() { return M; }
240 };
241
KeepLambdas()242 void KeepLambdas() {
243 auto F = +[]() { return 0; };
244 auto F2 = []() { return 0; };
245 }
246
247 template <class Base>
248 struct KeepWithDependentBase : public Base {
249 int M;
250 // We cannot make this method const because it might need to override
251 // a function from Base.
const_fKeep::KeepWithDependentBase252 int const_f() { return M; }
253 };
254
255 template <class T>
256 struct KeepClassTemplate {
257 int M;
258 // We cannot make this method const because a specialization
259 // might use *this differently.
const_fKeep::KeepClassTemplate260 int const_f() { return M; }
261 };
262
263 struct KeepMemberFunctionTemplate {
264 int M;
265 // We cannot make this method const because a specialization
266 // might use *this differently.
267 template <class T>
const_fKeep::KeepMemberFunctionTemplate268 int const_f() { return M; }
269 };
270
instantiate()271 void instantiate() {
272 struct S {};
273 KeepWithDependentBase<S> I1;
274 I1.const_f();
275
276 KeepClassTemplate<int> I2;
277 I2.const_f();
278
279 KeepMemberFunctionTemplate I3;
280 I3.const_f<int>();
281 }
282
283 struct NoFixitInMacro {
284 int M;
285
286 #define FUN const_use_macro()
287 int FUN {
288 return M;
289 }
290
291 #define T(FunctionName, Keyword) \
292 int FunctionName() Keyword { return M; }
293 #define EMPTY
294 T(A, EMPTY)
295 T(B, const)
296
297 #define T2(FunctionName) \
298 int FunctionName() { return M; }
299 T2(A2)
300 };
301
302 // Real-world code, see clang::ObjCInterfaceDecl.
303 class DataPattern {
304 int &data() const;
305
306 public:
get() const307 const int &get() const {
308 return const_cast<DataPattern *>(this)->get();
309 }
310
311 // This member function must stay non-const, even though
312 // it only calls other private const member functions.
get()313 int &get() {
314 return data();
315 }
316
set()317 void set() {
318 data() = 42;
319 }
320 };
321
322 struct MemberFunctionPointer {
call_non_constKeep::MemberFunctionPointer323 void call_non_const(void (MemberFunctionPointer::*FP)()) {
324 (this->*FP)();
325 }
326
call_constKeep::MemberFunctionPointer327 void call_const(void (MemberFunctionPointer::*FP)() const) {
328 (this->*FP)();
329 }
330 };
331
332 } // namespace Keep
333