1// RUN: %check_clang_tidy %s readability-non-const-parameter %t
2
3// Currently the checker only warns about pointer arguments.
4//
5// It can be defined both that the data is const and that the pointer is const,
6// the checker only checks if the data can be const-specified.
7//
8// It does not warn about pointers to records or function pointers.
9
10// Some external function where first argument is nonconst and second is const.
11char *strcpy1(char *dest, const char *src);
12unsigned my_strcpy(char *buf, const char *s);
13unsigned my_strlen(const char *buf);
14
15// CHECK-MESSAGES: :[[@LINE+1]]:29: warning: pointer parameter 'last' can be pointer to const [readability-non-const-parameter]
16void warn1(int *first, int *last) {
17 // CHECK-FIXES: {{^}}void warn1(int *first, const int *last) {{{$}}
18 *first = 0;
19 if (first < last) {
20 } // <- last can be const
21}
22
23// TODO: warning should be written here
24void warn2(char *p) {
25 char buf[10];
26 strcpy1(dest: buf, src: p);
27}
28
29// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be
30void assign1(int *p) {
31 // CHECK-FIXES: {{^}}void assign1(const int *p) {{{$}}
32 const int *q;
33 q = p;
34}
35
36// CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be
37void assign2(int *p) {
38 // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}}
39 const int *q;
40 q = p + 1;
41}
42
43void assign3(int *p) {
44 *p = 0;
45}
46
47void assign4(int *p) {
48 *p += 2;
49}
50
51void assign5(char *p) {
52 p[0] = 0;
53}
54
55void assign6(int *p) {
56 int *q;
57 q = p++;
58}
59
60void assign7(char *p) {
61 char *a, *b;
62 a = b = p;
63}
64
65void assign8(char *a, char *b) {
66 char *x;
67 x = (a ? a : b);
68}
69
70void assign9(unsigned char *str, const unsigned int i) {
71 unsigned char *p;
72 for (p = str + i; *p;) {
73 }
74}
75
76void assign10(int *buf) {
77 int i, *p;
78 for (i = 0, p = buf; i < 10; i++, p++) {
79 *p = 1;
80 }
81}
82
83// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be
84void init1(int *p) {
85 // CHECK-FIXES: {{^}}void init1(const int *p) {{{$}}
86 const int *q = p;
87}
88
89// CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be
90void init2(int *p) {
91 // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}}
92 const int *q = p + 1;
93}
94
95void init3(int *p) {
96 int *q = p;
97}
98
99void init4(float *p) {
100 int *q = (int *)p;
101}
102
103void init5(int *p) {
104 int *i = p ? p : 0;
105}
106
107void init6(int *p) {
108 int *a[] = {p, p, 0};
109}
110
111void init7(int *p, int x) {
112 for (int *q = p + x - 1; 0; q++)
113 ;
114}
115
116// CHECK-MESSAGES: :[[@LINE+1]]:18: warning: pointer parameter 'p' can be
117int return1(int *p) {
118 // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}}
119 return *p;
120}
121
122// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be
123const int *return2(int *p) {
124 // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}}
125 return p;
126}
127
128// CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be
129const int *return3(int *p) {
130 // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}}
131 return p + 1;
132}
133
134// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be
135const char *return4(char *p) {
136 // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}}
137 return p ? p : "";
138}
139
140char *return5(char *s) {
141 return s;
142}
143
144char *return6(char *s) {
145 return s + 1;
146}
147
148char *return7(char *a, char *b) {
149 return a ? a : b;
150}
151
152char return8(int *p) {
153 return ++(*p);
154}
155
156void dontwarn1(int *p) {
157 ++(*p);
158}
159
160void dontwarn2(int *p) {
161 (*p)++;
162}
163
164int dontwarn3(_Atomic(int) * p) {
165 return *p;
166}
167
168void callFunction1(char *p) {
169 strcpy1(dest: p, src: "abc");
170}
171
172void callFunction2(char *p) {
173 strcpy1(dest: &p[0], src: "abc");
174}
175
176void callFunction3(char *p) {
177 strcpy1(dest: p + 2, src: "abc");
178}
179
180char *callFunction4(char *p) {
181 return strcpy1(dest: p, src: "abc");
182}
183
184unsigned callFunction5(char *buf) {
185 unsigned len = my_strlen(buf);
186 return len + my_strcpy(buf, s: "abc");
187}
188
189void f6(int **p);
190void callFunction6(int *p) { f6(p: &p); }
191
192typedef union { void *v; } t;
193void f7(t obj);
194void callFunction7(int *p) {
195 f7(obj: (t){.v: p});
196}
197
198void f8(int &x);
199void callFunction8(int *p) {
200 f8(x&: *p);
201}
202
203// Don't warn about nonconst function pointers that can be const.
204void functionpointer(double f(double), int x) {
205 f(x);
206}
207
208// TODO: This is a false positive.
209// CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be
210int functionpointer2(int *p) {
211 return *p;
212}
213void use_functionpointer2() {
214 int (*fp)(int *) = functionpointer2; // <- the parameter 'p' can't be const
215}
216
217// Don't warn about nonconst record pointers that can be const.
218struct XY {
219 int *x;
220 int *y;
221};
222void recordpointer(struct XY *xy) {
223 *(xy->x) = 0;
224}
225void recordInitList(int *x) {
226 XY xy = {.x: x, .y: nullptr};
227}
228
229struct XYConst {
230 int const *x;
231};
232// CHECK-MESSAGES: :[[@LINE+1]]:30: warning: pointer parameter 'x' can be pointer to const
233void recordInitListDiag(int *x) {
234 // CHECK-FIXES: {{^}}void recordInitListDiag(const int *x) {{{$}}
235 XYConst xy = {.x: x};
236}
237typedef XYConst XYConstAlias;
238// CHECK-MESSAGES: :[[@LINE+1]]:35: warning: pointer parameter 'x' can be pointer to const
239void recordInitListAliasDiag(int *x) {
240 // CHECK-FIXES: {{^}}void recordInitListAliasDiag(const int *x) {{{$}}
241 XYConstAlias xy = {.x: x};
242}
243
244class C {
245public:
246 C(int *p) : p(p) {}
247
248private:
249 int *p;
250};
251
252class C2 {
253public:
254 // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: pointer parameter 'p' can be
255 C2(int *p) : p(p) {}
256 // CHECK-FIXES: {{^}} C2(const int *p) : p(p) {}{{$}}
257
258private:
259 const int *p;
260};
261
262void tempObject(int *p) {
263 C c(p);
264}
265
266// avoid fp for const pointer array
267void constPointerArray(const char *remapped[][2]) {
268 const char *name = remapped[0][0];
269}
270
271class Warn {
272public:
273 // CHECK-MESSAGES: :[[@LINE+1]]:21: warning: pointer parameter 'p' can be
274 void doStuff(int *p) {
275 // CHECK-FIXES: {{^}} void doStuff(const int *p) {{{$}}
276 x = *p;
277 }
278
279private:
280 int x;
281};
282
283class Base {
284public:
285 // Ensure there is no false positive for this method. It is virtual.
286 virtual void doStuff(int *p) {
287 int x = *p;
288 }
289};
290
291class Derived : public Base {
292public:
293 // Ensure there is no false positive for this method. It overrides a method.
294 void doStuff(int *p) override {
295 int x = *p;
296 }
297};
298
299extern char foo(char *s); // 1
300// CHECK-FIXES: {{^}}extern char foo(const char *s); // 1{{$}}
301// CHECK-MESSAGES: :[[@LINE+1]]:16: warning: pointer parameter 's' can be
302char foo(char *s) {
303 // CHECK-FIXES: {{^}}char foo(const char *s) {{{$}}
304 return *s;
305}
306char foo(char *s); // 2
307// CHECK-FIXES: {{^}}char foo(const char *s); // 2{{$}}
308
309void lvalueReference(int *p) {
310 // CHECK-MESSAGES-NOT: warning: pointer parameter 'p' can be
311 int &x = *p;
312}
313
314// CHECK-MESSAGES: :[[@LINE+1]]:32: warning: pointer parameter 'p' can be
315void constLValueReference(int *p) {
316 // CHECK-FIXES: {{^}}void constLValueReference(const int *p) {{{$}}
317 const int &x = *p;
318}
319
320void lambdaLVRef(int *p) {
321 // CHECK-MESSAGES-NOT: warning: pointer parameter 'p' can be
322 auto foo = [&]() {
323 int &x = *p;
324 };
325}
326
327// CHECK-MESSAGES: :[[@LINE+1]]:28: warning: pointer parameter 'p' can be
328void lambdaConstLVRef(int *p) {
329 // CHECK-FIXES: {{^}}void lambdaConstLVRef(const int *p) {{{$}}
330 auto foo = [&]() {
331 const int &x = *p;
332 };
333}
334
335struct Temp1 {
336 Temp1(int &i) {
337 i = 10;
338 }
339};
340void constructLVRef(int *p) {
341 // CHECK-MESSAGES-NOT: warning: pointer parameter 'p' can be
342 Temp1 t(*p);
343}
344

source code of clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.cpp