xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.cpp (revision 89a1d03e2b379e325daa5249411e414bbd995b5e)
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(buf, 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(p, "abc");
170 }
171 
172 void callFunction2(char *p) {
173   strcpy1(&p[0], "abc");
174 }
175 
176 void callFunction3(char *p) {
177   strcpy1(p + 2, "abc");
178 }
179 
180 char *callFunction4(char *p) {
181   return strcpy1(p, "abc");
182 }
183 
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);
190 void callFunction6(int *p) { f6(&p); }
191 
192 typedef union { void *v; } t;
193 void f7(t obj);
194 void callFunction7(int *p) {
195   f7((t){p});
196 }
197 
198 void f8(int &x);
199 void callFunction8(int *p) {
200   f8(*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 
226 class C {
227 public:
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
237   C2(int *p) : p(p) {}
238   // CHECK-FIXES: {{^}}  C2(const int *p) : p(p) {}{{$}}
239 
240 private:
241   const int *p;
242 };
243 
244 void tempObject(int *p) {
245   C c(p);
246 }
247 
248 // avoid fp for const pointer array
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
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.
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.
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
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 
291 void lvalueReference(int *p) {
292   // CHECK-MESSAGES-NOT: warning: pointer parameter 'p' can be
293   int &x = *p;
294 }
295 
296 // CHECK-MESSAGES: :[[@LINE+1]]:32: warning: pointer parameter 'p' can be
297 void constLValueReference(int *p) {
298   // CHECK-FIXES: {{^}}void constLValueReference(const int *p) {{{$}}
299   const int &x = *p;
300 }
301 
302 void lambdaLVRef(int *p) {
303   // CHECK-MESSAGES-NOT: warning: pointer parameter 'p' can be
304   auto foo = [&]() {
305     int &x = *p;
306   };
307 }
308 
309 // CHECK-MESSAGES: :[[@LINE+1]]:28: warning: pointer parameter 'p' can be
310 void lambdaConstLVRef(int *p) {
311   // CHECK-FIXES: {{^}}void lambdaConstLVRef(const int *p) {{{$}}
312   auto foo = [&]() {
313     const int &x = *p;
314   };
315 }
316 
317 struct Temp1 {
318   Temp1(int &i) {
319     i = 10;
320   }
321 };
322 void constructLVRef(int *p) {
323   // CHECK-MESSAGES-NOT: warning: pointer parameter 'p' can be
324   Temp1 t(*p);
325 }
326