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