// RUN: %check_clang_tidy %s readability-non-const-parameter %t // Currently the checker only warns about pointer arguments. // // It can be defined both that the data is const and that the pointer is const, // the checker only checks if the data can be const-specified. // // It does not warn about pointers to records or function pointers. // Some external function where first argument is nonconst and second is const. char *strcpy1(char *dest, const char *src); unsigned my_strcpy(char *buf, const char *s); unsigned my_strlen(const char *buf); // CHECK-MESSAGES: :[[@LINE+1]]:29: warning: pointer parameter 'last' can be pointer to const [readability-non-const-parameter] void warn1(int *first, int *last) { // CHECK-FIXES: {{^}}void warn1(int *first, const int *last) {{{$}} *first = 0; if (first < last) { } // <- last can be const } // TODO: warning should be written here void warn2(char *p) { char buf[10]; strcpy1(buf, p); } // CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be void assign1(int *p) { // CHECK-FIXES: {{^}}void assign1(const int *p) {{{$}} const int *q; q = p; } // CHECK-MESSAGES: :[[@LINE+1]]:19: warning: pointer parameter 'p' can be void assign2(int *p) { // CHECK-FIXES: {{^}}void assign2(const int *p) {{{$}} const int *q; q = p + 1; } void assign3(int *p) { *p = 0; } void assign4(int *p) { *p += 2; } void assign5(char *p) { p[0] = 0; } void assign6(int *p) { int *q; q = p++; } void assign7(char *p) { char *a, *b; a = b = p; } void assign8(char *a, char *b) { char *x; x = (a ? a : b); } void assign9(unsigned char *str, const unsigned int i) { unsigned char *p; for (p = str + i; *p;) { } } void assign10(int *buf) { int i, *p; for (i = 0, p = buf; i < 10; i++, p++) { *p = 1; } } // CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be void init1(int *p) { // CHECK-FIXES: {{^}}void init1(const int *p) {{{$}} const int *q = p; } // CHECK-MESSAGES: :[[@LINE+1]]:17: warning: pointer parameter 'p' can be void init2(int *p) { // CHECK-FIXES: {{^}}void init2(const int *p) {{{$}} const int *q = p + 1; } void init3(int *p) { int *q = p; } void init4(float *p) { int *q = (int *)p; } void init5(int *p) { int *i = p ? p : 0; } void init6(int *p) { int *a[] = {p, p, 0}; } void init7(int *p, int x) { for (int *q = p + x - 1; 0; q++) ; } // CHECK-MESSAGES: :[[@LINE+1]]:18: warning: pointer parameter 'p' can be int return1(int *p) { // CHECK-FIXES: {{^}}int return1(const int *p) {{{$}} return *p; } // CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be const int *return2(int *p) { // CHECK-FIXES: {{^}}const int *return2(const int *p) {{{$}} return p; } // CHECK-MESSAGES: :[[@LINE+1]]:25: warning: pointer parameter 'p' can be const int *return3(int *p) { // CHECK-FIXES: {{^}}const int *return3(const int *p) {{{$}} return p + 1; } // CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be const char *return4(char *p) { // CHECK-FIXES: {{^}}const char *return4(const char *p) {{{$}} return p ? p : ""; } char *return5(char *s) { return s; } char *return6(char *s) { return s + 1; } char *return7(char *a, char *b) { return a ? a : b; } char return8(int *p) { return ++(*p); } void dontwarn1(int *p) { ++(*p); } void dontwarn2(int *p) { (*p)++; } int dontwarn3(_Atomic(int) * p) { return *p; } void callFunction1(char *p) { strcpy1(p, "abc"); } void callFunction2(char *p) { strcpy1(&p[0], "abc"); } void callFunction3(char *p) { strcpy1(p + 2, "abc"); } char *callFunction4(char *p) { return strcpy1(p, "abc"); } unsigned callFunction5(char *buf) { unsigned len = my_strlen(buf); return len + my_strcpy(buf, "abc"); } void f6(int **p); void callFunction6(int *p) { f6(&p); } typedef union { void *v; } t; void f7(t obj); void callFunction7(int *p) { f7((t){p}); } void f8(int &x); void callFunction8(int *p) { f8(*p); } // Don't warn about nonconst function pointers that can be const. void functionpointer(double f(double), int x) { f(x); } // TODO: This is a false positive. // CHECK-MESSAGES: :[[@LINE+1]]:27: warning: pointer parameter 'p' can be int functionpointer2(int *p) { return *p; } void use_functionpointer2() { int (*fp)(int *) = functionpointer2; // <- the parameter 'p' can't be const } // Don't warn about nonconst record pointers that can be const. struct XY { int *x; int *y; }; void recordpointer(struct XY *xy) { *(xy->x) = 0; } class C { public: C(int *p) : p(p) {} private: int *p; }; class C2 { public: // CHECK-MESSAGES: :[[@LINE+1]]:11: warning: pointer parameter 'p' can be C2(int *p) : p(p) {} // CHECK-FIXES: {{^}} C2(const int *p) : p(p) {}{{$}} private: const int *p; }; void tempObject(int *p) { C c(p); } // avoid fp for const pointer array void constPointerArray(const char *remapped[][2]) { const char *name = remapped[0][0]; } class Warn { public: // CHECK-MESSAGES: :[[@LINE+1]]:21: warning: pointer parameter 'p' can be void doStuff(int *p) { // CHECK-FIXES: {{^}} void doStuff(const int *p) {{{$}} x = *p; } private: int x; }; class Base { public: // Ensure there is no false positive for this method. It is virtual. virtual void doStuff(int *p) { int x = *p; } }; class Derived : public Base { public: // Ensure there is no false positive for this method. It overrides a method. void doStuff(int *p) override { int x = *p; } }; extern char foo(char *s); // 1 // CHECK-FIXES: {{^}}extern char foo(const char *s); // 1{{$}} // CHECK-MESSAGES: :[[@LINE+1]]:16: warning: pointer parameter 's' can be char foo(char *s) { // CHECK-FIXES: {{^}}char foo(const char *s) {{{$}} return *s; } char foo(char *s); // 2 // CHECK-FIXES: {{^}}char foo(const char *s); // 2{{$}}