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 voidForLoopUnsignedBound() { 50 unsigned size = 3147483647; 51 for (int i = 0; i < size; ++i) { 52 // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'unsigned int' [bugprone-too-small-loop-variable] 53 } 54 } 55 56 // The iteration's upper bound has a template dependent value. 57 template <long size> 58 void doSomething() { 59 for (short i = 0; i < size; ++i) { 60 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] 61 } 62 } 63 64 // The iteration's upper bound has a template dependent type. 65 template <class T> 66 void doSomething() { 67 for (T i = 0; i < size(); ++i) { 68 // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] 69 } 70 } 71 72 void voidForLoopInstantiation() { 73 // This line does not trigger the warning. 74 doSomething<long>(); 75 // This one triggers the warning. 76 doSomething<short>(); 77 } 78 79 // A suspicious function used in a macro. 80 #define SUSPICIOUS_SIZE (size()) 81 void voidBadForLoopWithMacroBound() { 82 for (short i = 0; i < SUSPICIOUS_SIZE; ++i) { 83 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] 84 } 85 } 86 87 //////////////////////////////////////////////////////////////////////////////// 88 /// Correct loops: we should not warn here. 89 90 // A simple use case when both expressions have the same type. 91 void voidGoodForLoop() { 92 for (long i = 0; i < size(); ++i) { // no warning 93 } 94 } 95 96 // Other use case where both expressions have the same type, 97 // but short expressions are converted to int by the compare operator. 98 void voidGoodForLoop2() { 99 short loopCond = 10; 100 for (short i = 0; i < loopCond; ++i) { // no warning 101 } 102 } 103 104 // Because of the integer literal, the iteration's upper bound is int, but we suppress the warning here. 105 void voidForLoopShortPlusLiteral() { 106 short size = 30000; 107 for (short i = 0; i <= (size - 1); ++i) { // no warning 108 } 109 } 110 111 // Addition of two short variables results in an int value, but we suppress this to avoid false positives. 112 void voidForLoopShortPlusShort() { 113 short size = 256; 114 short increment = 14; 115 for (short i = 0; i < size + increment; ++i) { // no warning 116 } 117 } 118 119 // In this test case we have different integer types, but here the loop variable has the bigger type. 120 // The iteration's bound is cast implicitly, not the loop variable. 121 void voidForLoopBoundImplicitCast() { 122 short start = 256; 123 short end = 14; 124 for (int i = start; i >= end; --i) { // no warning 125 } 126 } 127 128 // Range based loop and other iterator based loops are ignored by this check. 129 void voidRangeBasedForLoop() { 130 int array[] = {1, 2, 3, 4, 5}; 131 for (const int &i : array) { // no warning 132 } 133 } 134 135 //////////////////////////////////////////////////////////////////////////////// 136 /// Future possibilites to improve the check. 137 138 // False positive: because of the int literal, iteration's upper bound has int type. 139 void voidForLoopFalsePositive() { 140 short size = 30000; 141 bool cond = false; 142 for (short i = 0; i < (cond ? 0 : size); ++i) { 143 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable] 144 } 145 } 146 147 void voidForLoopFalsePositive2() { 148 short size = 30000; 149 bool cond = false; 150 for (short i = 0; i < (!cond ? size : 0); ++i) { 151 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable] 152 } 153 } 154 155 // False positive: The loop bound expression contains nested binary operators. 156 void voidForLoopFalsePositive3() { 157 short number = 30000; 158 for (short i = 0; i < ((number & 0x7f) + 1); ++i) { 159 // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable] 160 } 161 } 162 163 // TODO: handle while loop. 164 void voidBadWhileLoop() { 165 short i = 0; 166 while (i < size()) { // missing warning 167 ++i; 168 } 169 } 170 171 // TODO: handle do-while loop. 172 void voidBadDoWhileLoop() { 173 short i = 0; 174 do { 175 ++i; 176 } while (i < size()); // missing warning 177 } 178 179 // TODO: handle complex loop conditions. 180 void voidComplexForCond() { 181 bool additionalCond = true; 182 for (int i = 0; i < size() && additionalCond; ++i) { // missing warning 183 } 184 } 185 186 //////////////////////////////////////////////////////////////////////////////// 187 /// Suspicious test cases ingored by this check. 188 189 // Test case with a reverse iteration. 190 // This is caught by -Wimplicit-int-conversion. 191 void voidReverseForLoop() { 192 for (short i = size() - 1; i >= 0; --i) { // no warning 193 } 194 } 195 196 // Macro defined literals are used inside the loop condition. 197 #define SIZE 125 198 #define SIZE2 (SIZE + 1) 199 void voidForLoopWithMacroBound() { 200 for (short i = 0; i < SIZE2; ++i) { // no warning 201 } 202 } 203 204 // A suspicious loop is not caught if the iteration's upper bound is a literal. 205 void voidForLoopWithLiteralBound() { 206 for (short i = 0; i < 125; ++i) { // no warning 207 } 208 } 209 210 // The used literal leads to an infinite loop. 211 // This is caught by -Wtautological-constant-out-of-range-compare. 212 void voidForLoopWithBigLiteralBound() { 213 for (short i = 0; i < 294967296l; ++i) { // no warning 214 } 215 } 216 217 enum eSizeType { 218 START, 219 Y, 220 END 221 }; 222 223 // A suspicious loop is not caught if the iteration's upper bound is an enum value. 224 void voidForLoopWithEnumBound() { 225 for (short i = eSizeType::START; i < eSizeType::END; ++i) { // no warning 226 } 227 } 228 229 enum eSizeType2 : long { 230 START2 = 294967296l, 231 Y2, 232 END2 233 }; 234 235 // The used enum value leads to an infinite loop. 236 // This is caught by -Wtautological-constant-out-of-range-compare. 237 void voidForLoopWithBigEnumBound() { 238 for (short i = eSizeType2::START2; i < eSizeType2::END2; ++i) { // no warning 239 } 240 } 241 242 // A suspicious loop is not caught if the iteration's upper bound is a constant variable. 243 void voidForLoopWithConstBound() { 244 const long size = 252l; 245 for (short i = 0; i < size; ++i) { // no warning 246 } 247 } 248 249 // The used constant variable leads to an infinite loop. 250 // This is caught by -Wtautological-constant-out-of-range-compare. 251 void voidForLoopWithBigConstBound() { 252 const long size = 294967296l; 253 for (short i = 0; i < size; ++i) { // no warning 254 } 255 } 256