forked from OSchip/llvm-project
256 lines
8.0 KiB
C++
256 lines
8.0 KiB
C++
// RUN: %check_clang_tidy %s bugprone-too-small-loop-variable %t -- \
|
|
// RUN: -config="{CheckOptions: \
|
|
// RUN: [{key: bugprone-too-small-loop-variable.MagnitudeBitsUpperLimit, \
|
|
// RUN: value: 1024}]}" \
|
|
// RUN: -- --target=x86_64-linux
|
|
|
|
long size() { return 294967296l; }
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// Test cases correctly caught by bugprone-too-small-loop-variable.
|
|
|
|
void voidBadForLoop() {
|
|
for (int i = 0; i < size(); ++i) {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
|
|
}
|
|
}
|
|
|
|
void voidBadForLoop2() {
|
|
for (int i = 0; i < size() + 10; ++i) {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
|
|
}
|
|
}
|
|
|
|
void voidBadForLoop3() {
|
|
for (int i = 0; i <= size() - 1; ++i) {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
|
|
}
|
|
}
|
|
|
|
void voidBadForLoop4() {
|
|
for (int i = 0; size() > i; ++i) {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
|
|
}
|
|
}
|
|
|
|
void voidBadForLoop5() {
|
|
for (int i = 0; size() - 1 >= i; ++i) {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
|
|
}
|
|
}
|
|
|
|
void voidBadForLoop6() {
|
|
int i = 0;
|
|
for (; i < size(); ++i) {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
|
|
}
|
|
}
|
|
|
|
void voidForLoopUnsignedBound() {
|
|
unsigned size = 3147483647;
|
|
for (int i = 0; i < size; ++i) {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'unsigned int' [bugprone-too-small-loop-variable]
|
|
}
|
|
}
|
|
|
|
// The iteration's upper bound has a template dependent value.
|
|
template <long size>
|
|
void doSomething() {
|
|
for (short i = 0; i < size; ++i) {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
|
|
}
|
|
}
|
|
|
|
// The iteration's upper bound has a template dependent type.
|
|
template <class T>
|
|
void doSomething() {
|
|
for (T i = 0; i < size(); ++i) {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
|
|
}
|
|
}
|
|
|
|
void voidForLoopInstantiation() {
|
|
// This line does not trigger the warning.
|
|
doSomething<long>();
|
|
// This one triggers the warning.
|
|
doSomething<short>();
|
|
}
|
|
|
|
// A suspicious function used in a macro.
|
|
#define SUSPICIOUS_SIZE (size())
|
|
void voidBadForLoopWithMacroBound() {
|
|
for (short i = 0; i < SUSPICIOUS_SIZE; ++i) {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable]
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// Correct loops: we should not warn here.
|
|
|
|
// A simple use case when both expressions have the same type.
|
|
void voidGoodForLoop() {
|
|
for (long i = 0; i < size(); ++i) { // no warning
|
|
}
|
|
}
|
|
|
|
// Other use case where both expressions have the same type,
|
|
// but short expressions are converted to int by the compare operator.
|
|
void voidGoodForLoop2() {
|
|
short loopCond = 10;
|
|
for (short i = 0; i < loopCond; ++i) { // no warning
|
|
}
|
|
}
|
|
|
|
// Because of the integer literal, the iteration's upper bound is int, but we suppress the warning here.
|
|
void voidForLoopShortPlusLiteral() {
|
|
short size = 30000;
|
|
for (short i = 0; i <= (size - 1); ++i) { // no warning
|
|
}
|
|
}
|
|
|
|
// Addition of two short variables results in an int value, but we suppress this to avoid false positives.
|
|
void voidForLoopShortPlusShort() {
|
|
short size = 256;
|
|
short increment = 14;
|
|
for (short i = 0; i < size + increment; ++i) { // no warning
|
|
}
|
|
}
|
|
|
|
// In this test case we have different integer types, but here the loop variable has the bigger type.
|
|
// The iteration's bound is cast implicitly, not the loop variable.
|
|
void voidForLoopBoundImplicitCast() {
|
|
short start = 256;
|
|
short end = 14;
|
|
for (int i = start; i >= end; --i) { // no warning
|
|
}
|
|
}
|
|
|
|
// Range based loop and other iterator based loops are ignored by this check.
|
|
void voidRangeBasedForLoop() {
|
|
int array[] = {1, 2, 3, 4, 5};
|
|
for (const int &i : array) { // no warning
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// Future possibilites to improve the check.
|
|
|
|
// False positive: because of the int literal, iteration's upper bound has int type.
|
|
void voidForLoopFalsePositive() {
|
|
short size = 30000;
|
|
bool cond = false;
|
|
for (short i = 0; i < (cond ? 0 : size); ++i) {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable]
|
|
}
|
|
}
|
|
|
|
void voidForLoopFalsePositive2() {
|
|
short size = 30000;
|
|
bool cond = false;
|
|
for (short i = 0; i < (!cond ? size : 0); ++i) {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable]
|
|
}
|
|
}
|
|
|
|
// False positive: The loop bound expression contains nested binary operators.
|
|
void voidForLoopFalsePositive3() {
|
|
short number = 30000;
|
|
for (short i = 0; i < ((number & 0x7f) + 1); ++i) {
|
|
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable]
|
|
}
|
|
}
|
|
|
|
// TODO: handle while loop.
|
|
void voidBadWhileLoop() {
|
|
short i = 0;
|
|
while (i < size()) { // missing warning
|
|
++i;
|
|
}
|
|
}
|
|
|
|
// TODO: handle do-while loop.
|
|
void voidBadDoWhileLoop() {
|
|
short i = 0;
|
|
do {
|
|
++i;
|
|
} while (i < size()); // missing warning
|
|
}
|
|
|
|
// TODO: handle complex loop conditions.
|
|
void voidComplexForCond() {
|
|
bool additionalCond = true;
|
|
for (int i = 0; i < size() && additionalCond; ++i) { // missing warning
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
/// Suspicious test cases ingored by this check.
|
|
|
|
// Test case with a reverse iteration.
|
|
// This is caught by -Wimplicit-int-conversion.
|
|
void voidReverseForLoop() {
|
|
for (short i = size() - 1; i >= 0; --i) { // no warning
|
|
}
|
|
}
|
|
|
|
// Macro defined literals are used inside the loop condition.
|
|
#define SIZE 125
|
|
#define SIZE2 (SIZE + 1)
|
|
void voidForLoopWithMacroBound() {
|
|
for (short i = 0; i < SIZE2; ++i) { // no warning
|
|
}
|
|
}
|
|
|
|
// A suspicious loop is not caught if the iteration's upper bound is a literal.
|
|
void voidForLoopWithLiteralBound() {
|
|
for (short i = 0; i < 125; ++i) { // no warning
|
|
}
|
|
}
|
|
|
|
// The used literal leads to an infinite loop.
|
|
// This is caught by -Wtautological-constant-out-of-range-compare.
|
|
void voidForLoopWithBigLiteralBound() {
|
|
for (short i = 0; i < 294967296l; ++i) { // no warning
|
|
}
|
|
}
|
|
|
|
enum eSizeType {
|
|
START,
|
|
Y,
|
|
END
|
|
};
|
|
|
|
// A suspicious loop is not caught if the iteration's upper bound is an enum value.
|
|
void voidForLoopWithEnumBound() {
|
|
for (short i = eSizeType::START; i < eSizeType::END; ++i) { // no warning
|
|
}
|
|
}
|
|
|
|
enum eSizeType2 : long {
|
|
START2 = 294967296l,
|
|
Y2,
|
|
END2
|
|
};
|
|
|
|
// The used enum value leads to an infinite loop.
|
|
// This is caught by -Wtautological-constant-out-of-range-compare.
|
|
void voidForLoopWithBigEnumBound() {
|
|
for (short i = eSizeType2::START2; i < eSizeType2::END2; ++i) { // no warning
|
|
}
|
|
}
|
|
|
|
// A suspicious loop is not caught if the iteration's upper bound is a constant variable.
|
|
void voidForLoopWithConstBound() {
|
|
const long size = 252l;
|
|
for (short i = 0; i < size; ++i) { // no warning
|
|
}
|
|
}
|
|
|
|
// The used constant variable leads to an infinite loop.
|
|
// This is caught by -Wtautological-constant-out-of-range-compare.
|
|
void voidForLoopWithBigConstBound() {
|
|
const long size = 294967296l;
|
|
for (short i = 0; i < size; ++i) { // no warning
|
|
}
|
|
}
|