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