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