1 // RUN: %check_clang_tidy %s bugprone-too-small-loop-variable %t -- \ 2 // RUN: -config="{CheckOptions: \ 3 // RUN: {bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit: 1024}}" \ 4 // RUN: -- --target=x86_64-linux 5 6 long size() { return 294967296l; } 7 8 //////////////////////////////////////////////////////////////////////////////// 9 /// Test cases correctly caught by bugprone-too-small-loop-variable. 10 11 void voidBadForLoop() { 12 for (int i = 0; i < size(); ++i) { 13 // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] 14 } 15 } 16 17 void voidBadForLoop2() { 18 for (int i = 0; i < size() + 10; ++i) { 19 // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] 20 } 21 } 22 23 void voidBadForLoop3() { 24 for (int i = 0; i <= size() - 1; ++i) { 25 // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] 26 } 27 } 28 29 void voidBadForLoop4() { 30 for (int i = 0; size() > i; ++i) { 31 // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] 32 } 33 } 34 35 void voidBadForLoop5() { 36 for (int i = 0; size() - 1 >= i; ++i) { 37 // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] 38 } 39 } 40 41 void voidBadForLoop6() { 42 int i = 0; 43 for (; i < size(); ++i) { 44 // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] 45 } 46 } 47 48 void voidBadForLoop7() { 49 struct Int { 50 int value; 51 } i; 52 53 for (i.value = 0; i.value < size(); ++i.value) { 54 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] 55 } 56 } 57 58 void voidForLoopUnsignedBound() { 59 unsigned size = 3147483647; 60 for (int i = 0; i < size; ++i) { 61 // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'unsigned int' [bugprone-too-small-loop-variable] 62 } 63 } 64 65 // The iteration's upper bound has a template dependent value. 66 template <long size> 67 void doSomething() { 68 for (short i = 0; i < size; ++i) { 69 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] 70 } 71 } 72 73 // The iteration's upper bound has a template dependent type. 74 template <class T> 75 void doSomething() { 76 for (T i = 0; i < size(); ++i) { 77 // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] 78 } 79 } 80 81 void voidForLoopInstantiation() { 82 // This line does not trigger the warning. 83 doSomething<long>(); 84 // This one triggers the warning. 85 doSomething<short>(); 86 } 87 88 // A suspicious function used in a macro. 89 #define SUSPICIOUS_SIZE (size()) 90 void voidBadForLoopWithMacroBound() { 91 for (short i = 0; i < SUSPICIOUS_SIZE; ++i) { 92 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] 93 } 94 } 95 96 //////////////////////////////////////////////////////////////////////////////// 97 /// Correct loops: we should not warn here. 98 99 // A simple use case when both expressions have the same type. 100 void voidGoodForLoop() { 101 for (long i = 0; i < size(); ++i) { // no warning 102 } 103 } 104 105 // Other use case where both expressions have the same type, 106 // but short expressions are converted to int by the compare operator. 107 void voidGoodForLoop2() { 108 short loopCond = 10; 109 for (short i = 0; i < loopCond; ++i) { // no warning 110 } 111 } 112 113 // Because of the integer literal, the iteration's upper bound is int, but we suppress the warning here. 114 void voidForLoopShortPlusLiteral() { 115 short size = 30000; 116 for (short i = 0; i <= (size - 1); ++i) { // no warning 117 } 118 } 119 120 // Addition of two short variables results in an int value, but we suppress this to avoid false positives. 121 void voidForLoopShortPlusShort() { 122 short size = 256; 123 short increment = 14; 124 for (short i = 0; i < size + increment; ++i) { // no warning 125 } 126 } 127 128 // In this test case we have different integer types, but here the loop variable has the bigger type. 129 // The iteration's bound is cast implicitly, not the loop variable. 130 void voidForLoopBoundImplicitCast() { 131 short start = 256; 132 short end = 14; 133 for (int i = start; i >= end; --i) { // no warning 134 } 135 } 136 137 // Range based loop and other iterator based loops are ignored by this check. 138 void voidRangeBasedForLoop() { 139 int array[] = {1, 2, 3, 4, 5}; 140 for (const int &i : array) { // no warning 141 } 142 } 143 144 //////////////////////////////////////////////////////////////////////////////// 145 /// Future possibilites to improve the check. 146 147 // False positive: because of the int literal, iteration's upper bound has int type. 148 void voidForLoopFalsePositive() { 149 short size = 30000; 150 bool cond = false; 151 for (short i = 0; i < (cond ? 0 : size); ++i) { 152 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable] 153 } 154 } 155 156 void voidForLoopFalsePositive2() { 157 short size = 30000; 158 bool cond = false; 159 for (short i = 0; i < (!cond ? size : 0); ++i) { 160 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable] 161 } 162 } 163 164 // False positive: The loop bound expression contains nested binary operators. 165 void voidForLoopFalsePositive3() { 166 short number = 30000; 167 for (short i = 0; i < ((number & 0x7f) + 1); ++i) { 168 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable] 169 } 170 } 171 172 // TODO: handle while loop. 173 void voidBadWhileLoop() { 174 short i = 0; 175 while (i < size()) { // missing warning 176 ++i; 177 } 178 } 179 180 // TODO: handle do-while loop. 181 void voidBadDoWhileLoop() { 182 short i = 0; 183 do { 184 ++i; 185 } while (i < size()); // missing warning 186 } 187 188 // TODO: handle complex loop conditions. 189 void voidComplexForCond() { 190 bool additionalCond = true; 191 for (int i = 0; i < size() && additionalCond; ++i) { // missing warning 192 } 193 } 194 195 //////////////////////////////////////////////////////////////////////////////// 196 /// Suspicious test cases ingored by this check. 197 198 // Test case with a reverse iteration. 199 // This is caught by -Wimplicit-int-conversion. 200 void voidReverseForLoop() { 201 for (short i = size() - 1; i >= 0; --i) { // no warning 202 } 203 } 204 205 // Macro defined literals are used inside the loop condition. 206 #define SIZE 125 207 #define SIZE2 (SIZE + 1) 208 void voidForLoopWithMacroBound() { 209 for (short i = 0; i < SIZE2; ++i) { // no warning 210 } 211 } 212 213 // A suspicious loop is not caught if the iteration's upper bound is a literal. 214 void voidForLoopWithLiteralBound() { 215 for (short i = 0; i < 125; ++i) { // no warning 216 } 217 } 218 219 // The used literal leads to an infinite loop. 220 // This is caught by -Wtautological-constant-out-of-range-compare. 221 void voidForLoopWithBigLiteralBound() { 222 for (short i = 0; i < 294967296l; ++i) { // no warning 223 } 224 } 225 226 enum eSizeType { 227 START, 228 Y, 229 END 230 }; 231 232 // A suspicious loop is not caught if the iteration's upper bound is an enum value. 233 void voidForLoopWithEnumBound() { 234 for (short i = eSizeType::START; i < eSizeType::END; ++i) { // no warning 235 } 236 } 237 238 enum eSizeType2 : long { 239 START2 = 294967296l, 240 Y2, 241 END2 242 }; 243 244 // The used enum value leads to an infinite loop. 245 // This is caught by -Wtautological-constant-out-of-range-compare. 246 void voidForLoopWithBigEnumBound() { 247 for (short i = eSizeType2::START2; i < eSizeType2::END2; ++i) { // no warning 248 } 249 } 250 251 // A suspicious loop is not caught if the iteration's upper bound is a constant variable. 252 void voidForLoopWithConstBound() { 253 const long size = 252l; 254 for (short i = 0; i < size; ++i) { // no warning 255 } 256 } 257 258 // The used constant variable leads to an infinite loop. 259 // This is caught by -Wtautological-constant-out-of-range-compare. 260 void voidForLoopWithBigConstBound() { 261 const long size = 294967296l; 262 for (short i = 0; i < size; ++i) { // no warning 263 } 264 } 265 266 // Should detect proper size of upper bound bitfield 267 void voidForLoopWithBitfieldOnUpperBound() { 268 struct StructWithBitField { 269 unsigned bitfield : 5; 270 } value = {}; 271 272 for(unsigned char i = 0U; i < value.bitfield; ++i) { // no warning 273 } 274 } 275 276 // Should detect proper size of loop variable bitfield 277 void voidForLoopWithBitfieldOnLoopVar() { 278 struct StructWithBitField { 279 unsigned bitfield : 9; 280 } value = {}; 281 282 unsigned char upperLimit = 100U; 283 284 for(value.bitfield = 0U; value.bitfield < upperLimit; ++value.bitfield) { 285 } 286 } 287 288 // Should detect proper size of loop variable and upper bound 289 void voidForLoopWithBitfieldOnLoopVarAndUpperBound() { 290 struct StructWithBitField { 291 unsigned var : 5, limit : 4; 292 } value = {}; 293 294 for(value.var = 0U; value.var < value.limit; ++value.var) { 295 } 296 } 297 298 // Should detect proper size of loop variable and upper bound on integers 299 void voidForLoopWithBitfieldOnLoopVarAndUpperBoundOnInt() { 300 struct StructWithBitField { 301 unsigned var : 5; 302 int limit : 6; 303 } value = {}; 304 305 for(value.var = 0U; value.var < value.limit; ++value.var) { 306 } 307 } 308 309 void badForLoopWithBitfieldOnUpperBound() { 310 struct StructWithBitField { 311 unsigned bitfield : 9; 312 } value = {}; 313 314 for(unsigned char i = 0U; i < value.bitfield; ++i) { 315 // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: loop variable has narrower type 'unsigned char' than iteration's upper bound 'unsigned int:9' [bugprone-too-small-loop-variable] 316 } 317 } 318 319 void badForLoopWithBitfieldOnLoopVar() { 320 struct StructWithBitField { 321 unsigned bitfield : 7; 322 } value = {}; 323 324 unsigned char upperLimit = 100U; 325 326 for(value.bitfield = 0U; value.bitfield < upperLimit; ++value.bitfield) { 327 // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: loop variable has narrower type 'unsigned int:7' than iteration's upper bound 'unsigned char' [bugprone-too-small-loop-variable] 328 } 329 } 330 331 void badForLoopWithBitfieldOnLoopVarAndUpperBound() { 332 struct StructWithBitField { 333 unsigned var : 5, limit : 6; 334 } value = {}; 335 336 for(value.var = 0U; value.var < value.limit; ++value.var) { 337 // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: loop variable has narrower type 'unsigned int:5' than iteration's upper bound 'unsigned int:6' [bugprone-too-small-loop-variable] 338 } 339 } 340 341 void badForLoopWithBitfieldOnLoopVarOnIntAndUpperBound() { 342 struct StructWithBitField { 343 int var : 5; 344 unsigned limit : 5; 345 } value = {}; 346 347 for(value.var = 0U; value.var < value.limit; ++value.var) { 348 // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: loop variable has narrower type 'int:5' than iteration's upper bound 'unsigned int:5' [bugprone-too-small-loop-variable] 349 } 350 } 351 352 void badForLoopWithBitfieldOnLoopVarAndUpperBoundOnInt() { 353 struct StructWithBitField { 354 unsigned var : 5; 355 int limit : 7; 356 } value = {}; 357 358 for(value.var = 0U; value.var < value.limit; ++value.var) { 359 // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: loop variable has narrower type 'unsigned int:5' than iteration's upper bound 'int:7' [bugprone-too-small-loop-variable] 360 } 361 } 362 363 void badForLoopWithBitfieldOnLoopVarAndUpperBoundOnPtr() { 364 struct StructWithBitField { 365 unsigned var : 5, limit : 6; 366 } value = {}; 367 368 StructWithBitField* ptr = &value; 369 370 for(ptr->var = 0U; ptr->var < ptr->limit; ++ptr->var) { 371 // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: loop variable has narrower type 'unsigned int:5' than iteration's upper bound 'unsigned int:6' [bugprone-too-small-loop-variable] 372 } 373 } 374 375 void goodForLoopWithBitfieldOnUpperBoundOnly() { 376 struct S { 377 int x : 4; 378 } s; 379 380 for (int i = 10; i > s.x; --i) { 381 } 382 } 383 384 void goodForLoopWithIntegersOnUpperBoundOnly() { 385 struct S { 386 short x; 387 } s; 388 389 for (int i = 10; i > s.x; --i) { 390 } 391 } 392