xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.cpp (revision 1c9412441b87eb15262fb46dddd53015ff30c42d)
189a1d03eSRichard // RUN: %check_clang_tidy %s readability-non-const-parameter %t
289a1d03eSRichard 
389a1d03eSRichard // Currently the checker only warns about pointer arguments.
489a1d03eSRichard //
589a1d03eSRichard // It can be defined both that the data is const and that the pointer is const,
689a1d03eSRichard // the checker only checks if the data can be const-specified.
789a1d03eSRichard //
889a1d03eSRichard // It does not warn about pointers to records or function pointers.
989a1d03eSRichard 
1089a1d03eSRichard // Some external function where first argument is nonconst and second is const.
1189a1d03eSRichard char *strcpy1(char *dest, const char *src);
1289a1d03eSRichard unsigned my_strcpy(char *buf, const char *s);
1389a1d03eSRichard unsigned my_strlen(const char *buf);
1489a1d03eSRichard 
1589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE+1]]:29: warning: pointer parameter 'last' can be pointer to const [readability-non-const-parameter]
warn1(int * first,int * last)1689a1d03eSRichard void warn1(int *first, int *last) {
1789a1d03eSRichard   // CHECK-FIXES: {{^}}void warn1(int *first, const int *last) {{{$}}
1889a1d03eSRichard   *first = 0;
1989a1d03eSRichard   if (first < last) {
2089a1d03eSRichard   } // <- last can be const
2189a1d03eSRichard }
2289a1d03eSRichard 
2389a1d03eSRichard // TODO: warning should be written here
warn2(char * p)2489a1d03eSRichard void warn2(char *p) {
2589a1d03eSRichard   char buf[10];
2689a1d03eSRichard   strcpy1(buf, p);
2789a1d03eSRichard }
2889a1d03eSRichard 
2989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be
assign1(int * p)3089a1d03eSRichard void assign1(int *p) {
3189a1d03eSRichard   // CHECK-FIXES: {{^}}void assign1(const int *p) {{{$}}
3289a1d03eSRichard   const int *q;
3389a1d03eSRichard   q = p;
3489a1d03eSRichard }
3589a1d03eSRichard 
3689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be
assign2(int * p)3789a1d03eSRichard void assign2(int *p) {
3889a1d03eSRichard   // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}}
3989a1d03eSRichard   const int *q;
4089a1d03eSRichard   q = p + 1;
4189a1d03eSRichard }
4289a1d03eSRichard 
assign3(int * p)4389a1d03eSRichard void assign3(int *p) {
4489a1d03eSRichard   *p = 0;
4589a1d03eSRichard }
4689a1d03eSRichard 
assign4(int * p)4789a1d03eSRichard void assign4(int *p) {
4889a1d03eSRichard   *p += 2;
4989a1d03eSRichard }
5089a1d03eSRichard 
assign5(char * p)5189a1d03eSRichard void assign5(char *p) {
5289a1d03eSRichard   p[0] = 0;
5389a1d03eSRichard }
5489a1d03eSRichard 
assign6(int * p)5589a1d03eSRichard void assign6(int *p) {
5689a1d03eSRichard   int *q;
5789a1d03eSRichard   q = p++;
5889a1d03eSRichard }
5989a1d03eSRichard 
assign7(char * p)6089a1d03eSRichard void assign7(char *p) {
6189a1d03eSRichard   char *a, *b;
6289a1d03eSRichard   a = b = p;
6389a1d03eSRichard }
6489a1d03eSRichard 
assign8(char * a,char * b)6589a1d03eSRichard void assign8(char *a, char *b) {
6689a1d03eSRichard   char *x;
6789a1d03eSRichard   x = (a ? a : b);
6889a1d03eSRichard }
6989a1d03eSRichard 
assign9(unsigned char * str,const unsigned int i)7089a1d03eSRichard void assign9(unsigned char *str, const unsigned int i) {
7189a1d03eSRichard   unsigned char *p;
7289a1d03eSRichard   for (p = str + i; *p;) {
7389a1d03eSRichard   }
7489a1d03eSRichard }
7589a1d03eSRichard 
assign10(int * buf)7689a1d03eSRichard void assign10(int *buf) {
7789a1d03eSRichard   int i, *p;
7889a1d03eSRichard   for (i = 0, p = buf; i < 10; i++, p++) {
7989a1d03eSRichard     *p = 1;
8089a1d03eSRichard   }
8189a1d03eSRichard }
8289a1d03eSRichard 
8389a1d03eSRichard // CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be
init1(int * p)8489a1d03eSRichard void init1(int *p) {
8589a1d03eSRichard   // CHECK-FIXES: {{^}}void init1(const int *p) {{{$}}
8689a1d03eSRichard   const int *q = p;
8789a1d03eSRichard }
8889a1d03eSRichard 
8989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be
init2(int * p)9089a1d03eSRichard void init2(int *p) {
9189a1d03eSRichard   // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}}
9289a1d03eSRichard   const int *q = p + 1;
9389a1d03eSRichard }
9489a1d03eSRichard 
init3(int * p)9589a1d03eSRichard void init3(int *p) {
9689a1d03eSRichard   int *q = p;
9789a1d03eSRichard }
9889a1d03eSRichard 
init4(float * p)9989a1d03eSRichard void init4(float *p) {
10089a1d03eSRichard   int *q = (int *)p;
10189a1d03eSRichard }
10289a1d03eSRichard 
init5(int * p)10389a1d03eSRichard void init5(int *p) {
10489a1d03eSRichard   int *i = p ? p : 0;
10589a1d03eSRichard }
10689a1d03eSRichard 
init6(int * p)10789a1d03eSRichard void init6(int *p) {
10889a1d03eSRichard   int *a[] = {p, p, 0};
10989a1d03eSRichard }
11089a1d03eSRichard 
init7(int * p,int x)11189a1d03eSRichard void init7(int *p, int x) {
11289a1d03eSRichard   for (int *q = p + x - 1; 0; q++)
11389a1d03eSRichard     ;
11489a1d03eSRichard }
11589a1d03eSRichard 
11689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE+1]]:18: warning: pointer parameter 'p' can be
return1(int * p)11789a1d03eSRichard int return1(int *p) {
11889a1d03eSRichard   // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}}
11989a1d03eSRichard   return *p;
12089a1d03eSRichard }
12189a1d03eSRichard 
12289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be
return2(int * p)12389a1d03eSRichard const int *return2(int *p) {
12489a1d03eSRichard   // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}}
12589a1d03eSRichard   return p;
12689a1d03eSRichard }
12789a1d03eSRichard 
12889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be
return3(int * p)12989a1d03eSRichard const int *return3(int *p) {
13089a1d03eSRichard   // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}}
13189a1d03eSRichard   return p + 1;
13289a1d03eSRichard }
13389a1d03eSRichard 
13489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be
return4(char * p)13589a1d03eSRichard const char *return4(char *p) {
13689a1d03eSRichard   // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}}
13789a1d03eSRichard   return p ? p : "";
13889a1d03eSRichard }
13989a1d03eSRichard 
return5(char * s)14089a1d03eSRichard char *return5(char *s) {
14189a1d03eSRichard   return s;
14289a1d03eSRichard }
14389a1d03eSRichard 
return6(char * s)14489a1d03eSRichard char *return6(char *s) {
14589a1d03eSRichard   return s + 1;
14689a1d03eSRichard }
14789a1d03eSRichard 
return7(char * a,char * b)14889a1d03eSRichard char *return7(char *a, char *b) {
14989a1d03eSRichard   return a ? a : b;
15089a1d03eSRichard }
15189a1d03eSRichard 
return8(int * p)15289a1d03eSRichard char return8(int *p) {
15389a1d03eSRichard   return ++(*p);
15489a1d03eSRichard }
15589a1d03eSRichard 
dontwarn1(int * p)15689a1d03eSRichard void dontwarn1(int *p) {
15789a1d03eSRichard   ++(*p);
15889a1d03eSRichard }
15989a1d03eSRichard 
dontwarn2(int * p)16089a1d03eSRichard void dontwarn2(int *p) {
16189a1d03eSRichard   (*p)++;
16289a1d03eSRichard }
16389a1d03eSRichard 
dontwarn3(_Atomic (int)* p)16489a1d03eSRichard int dontwarn3(_Atomic(int) * p) {
16589a1d03eSRichard   return *p;
16689a1d03eSRichard }
16789a1d03eSRichard 
callFunction1(char * p)16889a1d03eSRichard void callFunction1(char *p) {
16989a1d03eSRichard   strcpy1(p, "abc");
17089a1d03eSRichard }
17189a1d03eSRichard 
callFunction2(char * p)17289a1d03eSRichard void callFunction2(char *p) {
17389a1d03eSRichard   strcpy1(&p[0], "abc");
17489a1d03eSRichard }
17589a1d03eSRichard 
callFunction3(char * p)17689a1d03eSRichard void callFunction3(char *p) {
17789a1d03eSRichard   strcpy1(p + 2, "abc");
17889a1d03eSRichard }
17989a1d03eSRichard 
callFunction4(char * p)18089a1d03eSRichard char *callFunction4(char *p) {
18189a1d03eSRichard   return strcpy1(p, "abc");
18289a1d03eSRichard }
18389a1d03eSRichard 
callFunction5(char * buf)18489a1d03eSRichard unsigned callFunction5(char *buf) {
18589a1d03eSRichard   unsigned len = my_strlen(buf);
18689a1d03eSRichard   return len + my_strcpy(buf, "abc");
18789a1d03eSRichard }
18889a1d03eSRichard 
18989a1d03eSRichard void f6(int **p);
callFunction6(int * p)19089a1d03eSRichard void callFunction6(int *p) { f6(&p); }
19189a1d03eSRichard 
19289a1d03eSRichard typedef union { void *v; } t;
19389a1d03eSRichard void f7(t obj);
callFunction7(int * p)19489a1d03eSRichard void callFunction7(int *p) {
19589a1d03eSRichard   f7((t){p});
19689a1d03eSRichard }
19789a1d03eSRichard 
19889a1d03eSRichard void f8(int &x);
callFunction8(int * p)19989a1d03eSRichard void callFunction8(int *p) {
20089a1d03eSRichard   f8(*p);
20189a1d03eSRichard }
20289a1d03eSRichard 
20389a1d03eSRichard // Don't warn about nonconst function pointers that can be const.
functionpointer(double f (double),int x)20489a1d03eSRichard void functionpointer(double f(double), int x) {
20589a1d03eSRichard   f(x);
20689a1d03eSRichard }
20789a1d03eSRichard 
20889a1d03eSRichard // TODO: This is a false positive.
20989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be
functionpointer2(int * p)21089a1d03eSRichard int functionpointer2(int *p) {
21189a1d03eSRichard   return *p;
21289a1d03eSRichard }
use_functionpointer2()21389a1d03eSRichard void use_functionpointer2() {
21489a1d03eSRichard   int (*fp)(int *) = functionpointer2; // <- the parameter 'p' can't be const
21589a1d03eSRichard }
21689a1d03eSRichard 
21789a1d03eSRichard // Don't warn about nonconst record pointers that can be const.
21889a1d03eSRichard struct XY {
21989a1d03eSRichard   int *x;
22089a1d03eSRichard   int *y;
22189a1d03eSRichard };
recordpointer(struct XY * xy)22289a1d03eSRichard void recordpointer(struct XY *xy) {
22389a1d03eSRichard   *(xy->x) = 0;
22489a1d03eSRichard }
recordInitList(int * x)225*1c941244SCongcong Cai void recordInitList(int *x) {
226*1c941244SCongcong Cai   XY xy = {x, nullptr};
227*1c941244SCongcong Cai }
228*1c941244SCongcong Cai 
229*1c941244SCongcong Cai struct XYConst {
230*1c941244SCongcong Cai   int const *x;
231*1c941244SCongcong Cai };
232*1c941244SCongcong Cai // CHECK-MESSAGES: :[[@LINE+1]]:30: warning: pointer parameter 'x' can be pointer to const
recordInitListDiag(int * x)233*1c941244SCongcong Cai void recordInitListDiag(int *x) {
234*1c941244SCongcong Cai   // CHECK-FIXES: {{^}}void recordInitListDiag(const int *x) {{{$}}
235*1c941244SCongcong Cai   XYConst xy = {x};
236*1c941244SCongcong Cai }
237*1c941244SCongcong Cai typedef XYConst XYConstAlias;
238*1c941244SCongcong Cai // CHECK-MESSAGES: :[[@LINE+1]]:35: warning: pointer parameter 'x' can be pointer to const
recordInitListAliasDiag(int * x)239*1c941244SCongcong Cai void recordInitListAliasDiag(int *x) {
240*1c941244SCongcong Cai   // CHECK-FIXES: {{^}}void recordInitListAliasDiag(const int *x) {{{$}}
241*1c941244SCongcong Cai   XYConstAlias xy = {x};
242*1c941244SCongcong Cai }
24389a1d03eSRichard 
24489a1d03eSRichard class C {
24589a1d03eSRichard public:
C(int * p)24689a1d03eSRichard   C(int *p) : p(p) {}
24789a1d03eSRichard 
24889a1d03eSRichard private:
24989a1d03eSRichard   int *p;
25089a1d03eSRichard };
25189a1d03eSRichard 
25289a1d03eSRichard class C2 {
25389a1d03eSRichard public:
25489a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: pointer parameter 'p' can be
C2(int * p)25589a1d03eSRichard   C2(int *p) : p(p) {}
25689a1d03eSRichard   // CHECK-FIXES: {{^}}  C2(const int *p) : p(p) {}{{$}}
25789a1d03eSRichard 
25889a1d03eSRichard private:
25989a1d03eSRichard   const int *p;
26089a1d03eSRichard };
26189a1d03eSRichard 
tempObject(int * p)26289a1d03eSRichard void tempObject(int *p) {
26389a1d03eSRichard   C c(p);
26489a1d03eSRichard }
26589a1d03eSRichard 
26689a1d03eSRichard // avoid fp for const pointer array
constPointerArray(const char * remapped[][2])26789a1d03eSRichard void constPointerArray(const char *remapped[][2]) {
26889a1d03eSRichard   const char *name = remapped[0][0];
26989a1d03eSRichard }
27089a1d03eSRichard 
27189a1d03eSRichard class Warn {
27289a1d03eSRichard public:
27389a1d03eSRichard   // CHECK-MESSAGES: :[[@LINE+1]]:21: warning: pointer parameter 'p' can be
doStuff(int * p)27489a1d03eSRichard   void doStuff(int *p) {
27589a1d03eSRichard     // CHECK-FIXES: {{^}}  void doStuff(const int *p) {{{$}}
27689a1d03eSRichard     x = *p;
27789a1d03eSRichard   }
27889a1d03eSRichard 
27989a1d03eSRichard private:
28089a1d03eSRichard   int x;
28189a1d03eSRichard };
28289a1d03eSRichard 
28389a1d03eSRichard class Base {
28489a1d03eSRichard public:
28589a1d03eSRichard   // Ensure there is no false positive for this method. It is virtual.
doStuff(int * p)28689a1d03eSRichard   virtual void doStuff(int *p) {
28789a1d03eSRichard     int x = *p;
28889a1d03eSRichard   }
28989a1d03eSRichard };
29089a1d03eSRichard 
29189a1d03eSRichard class Derived : public Base {
29289a1d03eSRichard public:
29389a1d03eSRichard   // Ensure there is no false positive for this method. It overrides a method.
doStuff(int * p)29489a1d03eSRichard   void doStuff(int *p) override {
29589a1d03eSRichard     int x = *p;
29689a1d03eSRichard   }
29789a1d03eSRichard };
29889a1d03eSRichard 
29989a1d03eSRichard extern char foo(char *s); // 1
30089a1d03eSRichard // CHECK-FIXES: {{^}}extern char foo(const char *s); // 1{{$}}
30189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: pointer parameter 's' can be
foo(char * s)30289a1d03eSRichard char foo(char *s) {
30389a1d03eSRichard   // CHECK-FIXES: {{^}}char foo(const char *s) {{{$}}
30489a1d03eSRichard   return *s;
30589a1d03eSRichard }
30689a1d03eSRichard char foo(char *s); // 2
30789a1d03eSRichard // CHECK-FIXES: {{^}}char foo(const char *s); // 2{{$}}
30889a1d03eSRichard 
lvalueReference(int * p)30989a1d03eSRichard void lvalueReference(int *p) {
31089a1d03eSRichard   // CHECK-MESSAGES-NOT: warning: pointer parameter 'p' can be
31189a1d03eSRichard   int &x = *p;
31289a1d03eSRichard }
31389a1d03eSRichard 
31489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE+1]]:32: warning: pointer parameter 'p' can be
constLValueReference(int * p)31589a1d03eSRichard void constLValueReference(int *p) {
31689a1d03eSRichard   // CHECK-FIXES: {{^}}void constLValueReference(const int *p) {{{$}}
31789a1d03eSRichard   const int &x = *p;
31889a1d03eSRichard }
31989a1d03eSRichard 
lambdaLVRef(int * p)32089a1d03eSRichard void lambdaLVRef(int *p) {
32189a1d03eSRichard   // CHECK-MESSAGES-NOT: warning: pointer parameter 'p' can be
32289a1d03eSRichard   auto foo = [&]() {
32389a1d03eSRichard     int &x = *p;
32489a1d03eSRichard   };
32589a1d03eSRichard }
32689a1d03eSRichard 
32789a1d03eSRichard // CHECK-MESSAGES: :[[@LINE+1]]:28: warning: pointer parameter 'p' can be
lambdaConstLVRef(int * p)32889a1d03eSRichard void lambdaConstLVRef(int *p) {
32989a1d03eSRichard   // CHECK-FIXES: {{^}}void lambdaConstLVRef(const int *p) {{{$}}
33089a1d03eSRichard   auto foo = [&]() {
33189a1d03eSRichard     const int &x = *p;
33289a1d03eSRichard   };
33389a1d03eSRichard }
33489a1d03eSRichard 
33589a1d03eSRichard struct Temp1 {
Temp1Temp133689a1d03eSRichard   Temp1(int &i) {
33789a1d03eSRichard     i = 10;
33889a1d03eSRichard   }
33989a1d03eSRichard };
constructLVRef(int * p)34089a1d03eSRichard void constructLVRef(int *p) {
34189a1d03eSRichard   // CHECK-MESSAGES-NOT: warning: pointer parameter 'p' can be
34289a1d03eSRichard   Temp1 t(*p);
34389a1d03eSRichard }
344