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.
11 char *strcpy1(char *dest, const char *src);
12 unsigned my_strcpy(char *buf, const char *s);
13 unsigned 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]
warn1(int * first,int * last)16 void 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
warn2(char * p)24 void warn2(char *p) {
25 char buf[10];
26 strcpy1(buf, p);
27 }
28
29 // CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be
assign1(int * p)30 void 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
assign2(int * p)37 void assign2(int *p) {
38 // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}}
39 const int *q;
40 q = p + 1;
41 }
42
assign3(int * p)43 void assign3(int *p) {
44 *p = 0;
45 }
46
assign4(int * p)47 void assign4(int *p) {
48 *p += 2;
49 }
50
assign5(char * p)51 void assign5(char *p) {
52 p[0] = 0;
53 }
54
assign6(int * p)55 void assign6(int *p) {
56 int *q;
57 q = p++;
58 }
59
assign7(char * p)60 void assign7(char *p) {
61 char *a, *b;
62 a = b = p;
63 }
64
assign8(char * a,char * b)65 void assign8(char *a, char *b) {
66 char *x;
67 x = (a ? a : b);
68 }
69
assign9(unsigned char * str,const unsigned int i)70 void assign9(unsigned char *str, const unsigned int i) {
71 unsigned char *p;
72 for (p = str + i; *p;) {
73 }
74 }
75
assign10(int * buf)76 void 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
init1(int * p)84 void 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
init2(int * p)90 void init2(int *p) {
91 // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}}
92 const int *q = p + 1;
93 }
94
init3(int * p)95 void init3(int *p) {
96 int *q = p;
97 }
98
init4(float * p)99 void init4(float *p) {
100 int *q = (int *)p;
101 }
102
init5(int * p)103 void init5(int *p) {
104 int *i = p ? p : 0;
105 }
106
init6(int * p)107 void init6(int *p) {
108 int *a[] = {p, p, 0};
109 }
110
init7(int * p,int x)111 void 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
return1(int * p)117 int 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
return2(int * p)123 const 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
return3(int * p)129 const 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
return4(char * p)135 const char *return4(char *p) {
136 // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}}
137 return p ? p : "";
138 }
139
return5(char * s)140 char *return5(char *s) {
141 return s;
142 }
143
return6(char * s)144 char *return6(char *s) {
145 return s + 1;
146 }
147
return7(char * a,char * b)148 char *return7(char *a, char *b) {
149 return a ? a : b;
150 }
151
return8(int * p)152 char return8(int *p) {
153 return ++(*p);
154 }
155
dontwarn1(int * p)156 void dontwarn1(int *p) {
157 ++(*p);
158 }
159
dontwarn2(int * p)160 void dontwarn2(int *p) {
161 (*p)++;
162 }
163
dontwarn3(_Atomic (int)* p)164 int dontwarn3(_Atomic(int) * p) {
165 return *p;
166 }
167
callFunction1(char * p)168 void callFunction1(char *p) {
169 strcpy1(p, "abc");
170 }
171
callFunction2(char * p)172 void callFunction2(char *p) {
173 strcpy1(&p[0], "abc");
174 }
175
callFunction3(char * p)176 void callFunction3(char *p) {
177 strcpy1(p + 2, "abc");
178 }
179
callFunction4(char * p)180 char *callFunction4(char *p) {
181 return strcpy1(p, "abc");
182 }
183
callFunction5(char * buf)184 unsigned callFunction5(char *buf) {
185 unsigned len = my_strlen(buf);
186 return len + my_strcpy(buf, "abc");
187 }
188
189 void f6(int **p);
callFunction6(int * p)190 void callFunction6(int *p) { f6(&p); }
191
192 typedef union { void *v; } t;
193 void f7(t obj);
callFunction7(int * p)194 void callFunction7(int *p) {
195 f7((t){p});
196 }
197
198 void f8(int &x);
callFunction8(int * p)199 void callFunction8(int *p) {
200 f8(*p);
201 }
202
203 // Don't warn about nonconst function pointers that can be const.
functionpointer(double f (double),int x)204 void 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
functionpointer2(int * p)210 int functionpointer2(int *p) {
211 return *p;
212 }
use_functionpointer2()213 void 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.
218 struct XY {
219 int *x;
220 int *y;
221 };
recordpointer(struct XY * xy)222 void recordpointer(struct XY *xy) {
223 *(xy->x) = 0;
224 }
225
226 class C {
227 public:
C(int * p)228 C(int *p) : p(p) {}
229
230 private:
231 int *p;
232 };
233
234 class C2 {
235 public:
236 // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: pointer parameter 'p' can be
C2(int * p)237 C2(int *p) : p(p) {}
238 // CHECK-FIXES: {{^}} C2(const int *p) : p(p) {}{{$}}
239
240 private:
241 const int *p;
242 };
243
tempObject(int * p)244 void tempObject(int *p) {
245 C c(p);
246 }
247
248 // avoid fp for const pointer array
constPointerArray(const char * remapped[][2])249 void constPointerArray(const char *remapped[][2]) {
250 const char *name = remapped[0][0];
251 }
252
253 class Warn {
254 public:
255 // CHECK-MESSAGES: :[[@LINE+1]]:21: warning: pointer parameter 'p' can be
doStuff(int * p)256 void doStuff(int *p) {
257 // CHECK-FIXES: {{^}} void doStuff(const int *p) {{{$}}
258 x = *p;
259 }
260
261 private:
262 int x;
263 };
264
265 class Base {
266 public:
267 // Ensure there is no false positive for this method. It is virtual.
doStuff(int * p)268 virtual void doStuff(int *p) {
269 int x = *p;
270 }
271 };
272
273 class Derived : public Base {
274 public:
275 // Ensure there is no false positive for this method. It overrides a method.
doStuff(int * p)276 void doStuff(int *p) override {
277 int x = *p;
278 }
279 };
280
281 extern char foo(char *s); // 1
282 // CHECK-FIXES: {{^}}extern char foo(const char *s); // 1{{$}}
283 // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: pointer parameter 's' can be
foo(char * s)284 char foo(char *s) {
285 // CHECK-FIXES: {{^}}char foo(const char *s) {{{$}}
286 return *s;
287 }
288 char foo(char *s); // 2
289 // CHECK-FIXES: {{^}}char foo(const char *s); // 2{{$}}
290