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] |
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 |
24 | void 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 |
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 |
37 | void assign2(int *p) { |
38 | // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}} |
39 | const int *q; |
40 | q = p + 1; |
41 | } |
42 | |
43 | void assign3(int *p) { |
44 | *p = 0; |
45 | } |
46 | |
47 | void assign4(int *p) { |
48 | *p += 2; |
49 | } |
50 | |
51 | void assign5(char *p) { |
52 | p[0] = 0; |
53 | } |
54 | |
55 | void assign6(int *p) { |
56 | int *q; |
57 | q = p++; |
58 | } |
59 | |
60 | void assign7(char *p) { |
61 | char *a, *b; |
62 | a = b = p; |
63 | } |
64 | |
65 | void assign8(char *a, char *b) { |
66 | char *x; |
67 | x = (a ? a : b); |
68 | } |
69 | |
70 | void assign9(unsigned char *str, const unsigned int i) { |
71 | unsigned char *p; |
72 | for (p = str + i; *p;) { |
73 | } |
74 | } |
75 | |
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 |
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 |
90 | void init2(int *p) { |
91 | // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}} |
92 | const int *q = p + 1; |
93 | } |
94 | |
95 | void init3(int *p) { |
96 | int *q = p; |
97 | } |
98 | |
99 | void init4(float *p) { |
100 | int *q = (int *)p; |
101 | } |
102 | |
103 | void init5(int *p) { |
104 | int *i = p ? p : 0; |
105 | } |
106 | |
107 | void init6(int *p) { |
108 | int *a[] = {p, p, 0}; |
109 | } |
110 | |
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 |
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 |
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 |
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 |
135 | const char *return4(char *p) { |
136 | // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}} |
137 | return p ? p : "" ; |
138 | } |
139 | |
140 | char *return5(char *s) { |
141 | return s; |
142 | } |
143 | |
144 | char *return6(char *s) { |
145 | return s + 1; |
146 | } |
147 | |
148 | char *return7(char *a, char *b) { |
149 | return a ? a : b; |
150 | } |
151 | |
152 | char return8(int *p) { |
153 | return ++(*p); |
154 | } |
155 | |
156 | void dontwarn1(int *p) { |
157 | ++(*p); |
158 | } |
159 | |
160 | void dontwarn2(int *p) { |
161 | (*p)++; |
162 | } |
163 | |
164 | int dontwarn3(_Atomic(int) * p) { |
165 | return *p; |
166 | } |
167 | |
168 | void callFunction1(char *p) { |
169 | strcpy1(dest: p, src: "abc" ); |
170 | } |
171 | |
172 | void callFunction2(char *p) { |
173 | strcpy1(dest: &p[0], src: "abc" ); |
174 | } |
175 | |
176 | void callFunction3(char *p) { |
177 | strcpy1(dest: p + 2, src: "abc" ); |
178 | } |
179 | |
180 | char *callFunction4(char *p) { |
181 | return strcpy1(dest: p, src: "abc" ); |
182 | } |
183 | |
184 | unsigned callFunction5(char *buf) { |
185 | unsigned len = my_strlen(buf); |
186 | return len + my_strcpy(buf, s: "abc" ); |
187 | } |
188 | |
189 | void f6(int **p); |
190 | void callFunction6(int *p) { f6(p: &p); } |
191 | |
192 | typedef union { void *v; } t; |
193 | void f7(t obj); |
194 | void callFunction7(int *p) { |
195 | f7(obj: (t){.v: p}); |
196 | } |
197 | |
198 | void f8(int &x); |
199 | void callFunction8(int *p) { |
200 | f8(x&: *p); |
201 | } |
202 | |
203 | // Don't warn about nonconst function pointers that can be const. |
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 |
210 | int functionpointer2(int *p) { |
211 | return *p; |
212 | } |
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 | }; |
222 | void recordpointer(struct XY *xy) { |
223 | *(xy->x) = 0; |
224 | } |
225 | void recordInitList(int *x) { |
226 | XY xy = {.x: x, .y: nullptr}; |
227 | } |
228 | |
229 | struct XYConst { |
230 | int const *x; |
231 | }; |
232 | // CHECK-MESSAGES: :[[@LINE+1]]:30: warning: pointer parameter 'x' can be pointer to const |
233 | void recordInitListDiag(int *x) { |
234 | // CHECK-FIXES: {{^}}void recordInitListDiag(const int *x) {{{$}} |
235 | XYConst xy = {.x: x}; |
236 | } |
237 | typedef XYConst XYConstAlias; |
238 | // CHECK-MESSAGES: :[[@LINE+1]]:35: warning: pointer parameter 'x' can be pointer to const |
239 | void recordInitListAliasDiag(int *x) { |
240 | // CHECK-FIXES: {{^}}void recordInitListAliasDiag(const int *x) {{{$}} |
241 | XYConstAlias xy = {.x: x}; |
242 | } |
243 | |
244 | class C { |
245 | public: |
246 | C(int *p) : p(p) {} |
247 | |
248 | private: |
249 | int *p; |
250 | }; |
251 | |
252 | class C2 { |
253 | public: |
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 | |
258 | private: |
259 | const int *p; |
260 | }; |
261 | |
262 | void tempObject(int *p) { |
263 | C c(p); |
264 | } |
265 | |
266 | // avoid fp for const pointer array |
267 | void constPointerArray(const char *remapped[][2]) { |
268 | const char *name = remapped[0][0]; |
269 | } |
270 | |
271 | class Warn { |
272 | public: |
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 | |
279 | private: |
280 | int x; |
281 | }; |
282 | |
283 | class Base { |
284 | public: |
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 | |
291 | class Derived : public Base { |
292 | public: |
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 | |
299 | extern 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 |
302 | char foo(char *s) { |
303 | // CHECK-FIXES: {{^}}char foo(const char *s) {{{$}} |
304 | return *s; |
305 | } |
306 | char foo(char *s); // 2 |
307 | // CHECK-FIXES: {{^}}char foo(const char *s); // 2{{$}} |
308 | |
309 | void 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 |
315 | void constLValueReference(int *p) { |
316 | // CHECK-FIXES: {{^}}void constLValueReference(const int *p) {{{$}} |
317 | const int &x = *p; |
318 | } |
319 | |
320 | void 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 |
328 | void lambdaConstLVRef(int *p) { |
329 | // CHECK-FIXES: {{^}}void lambdaConstLVRef(const int *p) {{{$}} |
330 | auto foo = [&]() { |
331 | const int &x = *p; |
332 | }; |
333 | } |
334 | |
335 | struct Temp1 { |
336 | Temp1(int &i) { |
337 | i = 10; |
338 | } |
339 | }; |
340 | void constructLVRef(int *p) { |
341 | // CHECK-MESSAGES-NOT: warning: pointer parameter 'p' can be |
342 | Temp1 t(*p); |
343 | } |
344 | |