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