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