404 lines · cpp
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-linux5 6long size() { return 294967296l; }7 8////////////////////////////////////////////////////////////////////////////////9/// Test cases correctly caught by bugprone-too-small-loop-variable.10 11void 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 17void 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 23void 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 29void 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 35void 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 41void 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 48void 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 58void 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.66template <long size>67void 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.74template <class T>75void 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 81void 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())90void 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 96unsigned int getVal() {97 return 300;98}99 100// The iteration's upper bound has a function declaration.101void voidBadForLoop8() {102 const unsigned int l = getVal();103 for (unsigned char i = 0; i < l; ++i) {104 // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: loop variable has narrower type 'unsigned char' than iteration's upper bound 'const unsigned int' [bugprone-too-small-loop-variable]105 }106}107 108////////////////////////////////////////////////////////////////////////////////109/// Correct loops: we should not warn here.110 111// A simple use case when both expressions have the same type.112void voidGoodForLoop() {113 for (long i = 0; i < size(); ++i) { // no warning114 }115}116 117// Other use case where both expressions have the same type,118// but short expressions are converted to int by the compare operator.119void voidGoodForLoop2() {120 short loopCond = 10;121 for (short i = 0; i < loopCond; ++i) { // no warning122 }123}124 125// Because of the integer literal, the iteration's upper bound is int, but we suppress the warning here.126void voidForLoopShortPlusLiteral() {127 short size = 30000;128 for (short i = 0; i <= (size - 1); ++i) { // no warning129 }130}131 132// Addition of two short variables results in an int value, but we suppress this to avoid false positives.133void voidForLoopShortPlusShort() {134 short size = 256;135 short increment = 14;136 for (short i = 0; i < size + increment; ++i) { // no warning137 }138}139 140// In this test case we have different integer types, but here the loop variable has the bigger type.141// The iteration's bound is cast implicitly, not the loop variable.142void voidForLoopBoundImplicitCast() {143 short start = 256;144 short end = 14;145 for (int i = start; i >= end; --i) { // no warning146 }147}148 149// Range based loop and other iterator based loops are ignored by this check.150void voidRangeBasedForLoop() {151 int array[] = {1, 2, 3, 4, 5};152 for (const int &i : array) { // no warning153 }154}155 156////////////////////////////////////////////////////////////////////////////////157/// Future possibilites to improve the check.158 159// False positive: because of the int literal, iteration's upper bound has int type.160void voidForLoopFalsePositive() {161 short size = 30000;162 bool cond = false;163 for (short i = 0; i < (cond ? 0 : size); ++i) {164 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable]165 }166}167 168void voidForLoopFalsePositive2() {169 short size = 30000;170 bool cond = false;171 for (short i = 0; i < (!cond ? size : 0); ++i) {172 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable]173 }174}175 176// False positive: The loop bound expression contains nested binary operators.177void voidForLoopFalsePositive3() {178 short number = 30000;179 for (short i = 0; i < ((number & 0x7f) + 1); ++i) {180 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable]181 }182}183 184// TODO: handle while loop.185void voidBadWhileLoop() {186 short i = 0;187 while (i < size()) { // missing warning188 ++i;189 }190}191 192// TODO: handle do-while loop.193void voidBadDoWhileLoop() {194 short i = 0;195 do {196 ++i;197 } while (i < size()); // missing warning198}199 200// TODO: handle complex loop conditions.201void voidComplexForCond() {202 bool additionalCond = true;203 for (int i = 0; i < size() && additionalCond; ++i) { // missing warning204 }205}206 207////////////////////////////////////////////////////////////////////////////////208/// Suspicious test cases ingored by this check.209 210// Test case with a reverse iteration.211// This is caught by -Wimplicit-int-conversion.212void voidReverseForLoop() {213 for (short i = size() - 1; i >= 0; --i) { // no warning214 }215}216 217// Macro defined literals are used inside the loop condition.218#define SIZE 125219#define SIZE2 (SIZE + 1)220void voidForLoopWithMacroBound() {221 for (short i = 0; i < SIZE2; ++i) { // no warning222 }223}224 225// A suspicious loop is not caught if the iteration's upper bound is a literal.226void voidForLoopWithLiteralBound() {227 for (short i = 0; i < 125; ++i) { // no warning228 }229}230 231// The used literal leads to an infinite loop.232// This is caught by -Wtautological-constant-out-of-range-compare.233void voidForLoopWithBigLiteralBound() {234 for (short i = 0; i < 294967296l; ++i) { // no warning235 }236}237 238enum eSizeType {239 START,240 Y,241 END242};243 244// A suspicious loop is not caught if the iteration's upper bound is an enum value.245void voidForLoopWithEnumBound() {246 for (short i = eSizeType::START; i < eSizeType::END; ++i) { // no warning247 }248}249 250enum eSizeType2 : long {251 START2 = 294967296l,252 Y2,253 END2254};255 256// The used enum value leads to an infinite loop.257// This is caught by -Wtautological-constant-out-of-range-compare.258void voidForLoopWithBigEnumBound() {259 for (short i = eSizeType2::START2; i < eSizeType2::END2; ++i) { // no warning260 }261}262 263// A suspicious loop is not caught if the iteration's upper bound is a constant variable.264void voidForLoopWithConstBound() {265 const long size = 252l;266 for (short i = 0; i < size; ++i) { // no warning267 }268}269 270// The used constant variable leads to an infinite loop.271// This is caught by -Wtautological-constant-out-of-range-compare.272void voidForLoopWithBigConstBound() {273 const long size = 294967296l;274 for (short i = 0; i < size; ++i) { // no warning275 }276}277 278// Should detect proper size of upper bound bitfield279void voidForLoopWithBitfieldOnUpperBound() {280 struct StructWithBitField {281 unsigned bitfield : 5;282 } value = {};283 284 for(unsigned char i = 0U; i < value.bitfield; ++i) { // no warning285 }286}287 288// Should detect proper size of loop variable bitfield289void voidForLoopWithBitfieldOnLoopVar() {290 struct StructWithBitField {291 unsigned bitfield : 9;292 } value = {};293 294 unsigned char upperLimit = 100U;295 296 for(value.bitfield = 0U; value.bitfield < upperLimit; ++value.bitfield) {297 }298}299 300// Should detect proper size of loop variable and upper bound301void voidForLoopWithBitfieldOnLoopVarAndUpperBound() {302 struct StructWithBitField {303 unsigned var : 5, limit : 4;304 } value = {};305 306 for(value.var = 0U; value.var < value.limit; ++value.var) {307 }308}309 310// Should detect proper size of loop variable and upper bound on integers311void voidForLoopWithBitfieldOnLoopVarAndUpperBoundOnInt() {312 struct StructWithBitField {313 unsigned var : 5;314 int limit : 6;315 } value = {};316 317 for(value.var = 0U; value.var < value.limit; ++value.var) {318 }319}320 321void badForLoopWithBitfieldOnUpperBound() {322 struct StructWithBitField {323 unsigned bitfield : 9;324 } value = {};325 326 for(unsigned char i = 0U; i < value.bitfield; ++i) {327 // 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]328 }329}330 331void badForLoopWithBitfieldOnLoopVar() {332 struct StructWithBitField {333 unsigned bitfield : 7;334 } value = {};335 336 unsigned char upperLimit = 100U;337 338 for(value.bitfield = 0U; value.bitfield < upperLimit; ++value.bitfield) {339 // 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]340 }341}342 343void badForLoopWithBitfieldOnLoopVarAndUpperBound() {344 struct StructWithBitField {345 unsigned var : 5, limit : 6;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 'unsigned int:5' than iteration's upper bound 'unsigned int:6' [bugprone-too-small-loop-variable]350 }351}352 353void badForLoopWithBitfieldOnLoopVarOnIntAndUpperBound() {354 struct StructWithBitField {355 int var : 5;356 unsigned limit : 5;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 'int:5' than iteration's upper bound 'unsigned int:5' [bugprone-too-small-loop-variable]361 }362}363 364void badForLoopWithBitfieldOnLoopVarAndUpperBoundOnInt() {365 struct StructWithBitField {366 unsigned var : 5;367 int limit : 7;368 } value = {};369 370 for(value.var = 0U; value.var < value.limit; ++value.var) {371 // 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]372 }373}374 375void badForLoopWithBitfieldOnLoopVarAndUpperBoundOnPtr() {376 struct StructWithBitField {377 unsigned var : 5, limit : 6;378 } value = {};379 380 StructWithBitField* ptr = &value;381 382 for(ptr->var = 0U; ptr->var < ptr->limit; ++ptr->var) {383 // 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]384 }385}386 387void goodForLoopWithBitfieldOnUpperBoundOnly() {388 struct S {389 int x : 4;390 } s;391 392 for (int i = 10; i > s.x; --i) {393 }394}395 396void goodForLoopWithIntegersOnUpperBoundOnly() {397 struct S {398 short x;399 } s;400 401 for (int i = 10; i > s.x; --i) {402 }403}404