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