Refactoring to address some issues from #5895 (handling of unsigned numbers). Also adding a TODO testcase since the real issue (FP) is still not fixed
This commit is contained in:
parent
40d7baa6bb
commit
a7b82b5c28
4
Makefile
4
Makefile
|
@ -214,6 +214,7 @@ TESTOBJ = test/options.o \
|
||||||
test/testtimer.o \
|
test/testtimer.o \
|
||||||
test/testtoken.o \
|
test/testtoken.o \
|
||||||
test/testtokenize.o \
|
test/testtokenize.o \
|
||||||
|
test/testtokenlist.o \
|
||||||
test/testtype.o \
|
test/testtype.o \
|
||||||
test/testuninitvar.o \
|
test/testuninitvar.o \
|
||||||
test/testunusedfunctions.o \
|
test/testunusedfunctions.o \
|
||||||
|
@ -573,6 +574,9 @@ test/testtoken.o: test/testtoken.cpp lib/cxx11emu.h test/testsuite.h lib/errorlo
|
||||||
test/testtokenize.o: test/testtokenize.cpp lib/cxx11emu.h test/testsuite.h lib/errorlogger.h lib/config.h lib/suppressions.h test/redirect.h lib/library.h lib/mathlib.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h lib/settings.h lib/standards.h lib/timer.h lib/path.h lib/preprocessor.h
|
test/testtokenize.o: test/testtokenize.cpp lib/cxx11emu.h test/testsuite.h lib/errorlogger.h lib/config.h lib/suppressions.h test/redirect.h lib/library.h lib/mathlib.h lib/token.h lib/valueflow.h lib/tokenize.h lib/tokenlist.h lib/settings.h lib/standards.h lib/timer.h lib/path.h lib/preprocessor.h
|
||||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o test/testtokenize.o test/testtokenize.cpp
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o test/testtokenize.o test/testtokenize.cpp
|
||||||
|
|
||||||
|
test/testtokenlist.o: test/testtokenlist.cpp lib/cxx11emu.h test/testsuite.h lib/errorlogger.h lib/config.h lib/suppressions.h test/redirect.h lib/library.h lib/mathlib.h lib/token.h lib/valueflow.h lib/settings.h lib/standards.h lib/timer.h lib/tokenlist.h
|
||||||
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o test/testtokenlist.o test/testtokenlist.cpp
|
||||||
|
|
||||||
test/testtype.o: test/testtype.cpp lib/cxx11emu.h lib/preprocessor.h lib/config.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/symboldatabase.h lib/token.h lib/valueflow.h lib/mathlib.h lib/checktype.h lib/check.h lib/settings.h lib/library.h lib/standards.h lib/timer.h test/testsuite.h test/redirect.h test/testutils.h
|
test/testtype.o: test/testtype.cpp lib/cxx11emu.h lib/preprocessor.h lib/config.h lib/tokenize.h lib/errorlogger.h lib/suppressions.h lib/tokenlist.h lib/symboldatabase.h lib/token.h lib/valueflow.h lib/mathlib.h lib/checktype.h lib/check.h lib/settings.h lib/library.h lib/standards.h lib/timer.h test/testsuite.h test/redirect.h test/testutils.h
|
||||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o test/testtype.o test/testtype.cpp
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -std=c++0x -c -o test/testtype.o test/testtype.cpp
|
||||||
|
|
||||||
|
|
|
@ -525,7 +525,8 @@ static std::string invertOperatorForOperandSwap(std::string s)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool checkIntRelation(const std::string &op, const MathLib::bigint value1, const MathLib::bigint value2)
|
template <typename T>
|
||||||
|
static bool checkIntRelation(const std::string &op, const T value1, const T value2)
|
||||||
{
|
{
|
||||||
return (op == "==" && value1 == value2) ||
|
return (op == "==" && value1 == value2) ||
|
||||||
(op == "!=" && value1 != value2) ||
|
(op == "!=" && value1 != value2) ||
|
||||||
|
@ -543,7 +544,9 @@ static bool checkFloatRelation(const std::string &op, const double value1, const
|
||||||
(op == "<=" && value1 <= value2);
|
(op == "<=" && value1 <= value2);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T> static T getvalue(const int test, const T value1, const T value2)
|
|
||||||
|
template<class T>
|
||||||
|
static inline T getvalue(const int test, const T value1, const T value2)
|
||||||
{
|
{
|
||||||
// test:
|
// test:
|
||||||
// 1 => return value that is less than both value1 and value2
|
// 1 => return value that is less than both value1 and value2
|
||||||
|
@ -553,7 +556,7 @@ template<class T> static T getvalue(const int test, const T value1, const T valu
|
||||||
// 5 => return value that is larger than both value1 and value2
|
// 5 => return value that is larger than both value1 and value2
|
||||||
switch (test) {
|
switch (test) {
|
||||||
case 1: {
|
case 1: {
|
||||||
T ret = std::min(value1, value2);
|
const T ret = std::min(value1, value2);
|
||||||
if ((ret - (T)1) < ret)
|
if ((ret - (T)1) < ret)
|
||||||
return ret - (T)1;
|
return ret - (T)1;
|
||||||
else if ((ret / (T)2) < ret)
|
else if ((ret / (T)2) < ret)
|
||||||
|
@ -565,11 +568,19 @@ template<class T> static T getvalue(const int test, const T value1, const T valu
|
||||||
case 2:
|
case 2:
|
||||||
return value1;
|
return value1;
|
||||||
case 3:
|
case 3:
|
||||||
return (value1 + value2) / (T)2;
|
if (std::numeric_limits<T>::is_integer) {
|
||||||
|
const T min = std::min(value1, value2);
|
||||||
|
if (min== std::numeric_limits<T>::max())
|
||||||
|
return min;
|
||||||
|
else
|
||||||
|
return min+1; // see #5895
|
||||||
|
} else {
|
||||||
|
return (value1 + value2) / (T)2;
|
||||||
|
}
|
||||||
case 4:
|
case 4:
|
||||||
return value2;
|
return value2;
|
||||||
case 5: {
|
case 5: {
|
||||||
T ret = std::max(value1, value2);
|
const T ret = std::max(value1, value2);
|
||||||
if ((ret + (T)1) > ret)
|
if ((ret + (T)1) > ret)
|
||||||
return ret + (T)1;
|
return ret + (T)1;
|
||||||
else if ((ret / (T)2) > ret)
|
else if ((ret / (T)2) > ret)
|
||||||
|
@ -672,6 +683,13 @@ void CheckCondition::checkIncorrectLogicOperator()
|
||||||
if (isfloat && (op1 == "==" || op1 == "!=" || op2 == "==" || op2 == "!="))
|
if (isfloat && (op1 == "==" || op1 == "!=" || op2 == "==" || op2 == "!="))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
const double d1 = (isfloat) ? MathLib::toDoubleNumber(value1) : 0;
|
||||||
|
const double d2 = (isfloat) ? MathLib::toDoubleNumber(value2) : 0;
|
||||||
|
const MathLib::bigint i1 = (isfloat) ? 0 : MathLib::toLongNumber(value1);
|
||||||
|
const MathLib::bigint i2 = (isfloat) ? 0 : MathLib::toLongNumber(value2);
|
||||||
|
const bool useUnsignedInt = (std::numeric_limits<MathLib::bigint>::max()==i1)||(std::numeric_limits<MathLib::bigint>::max()==i2);
|
||||||
|
const MathLib::biguint u1 = (useUnsignedInt) ? MathLib::toLongNumber(value1) : 0;
|
||||||
|
const MathLib::biguint u2 = (useUnsignedInt) ? MathLib::toLongNumber(value2) : 0;
|
||||||
// evaluate if expression is always true/false
|
// evaluate if expression is always true/false
|
||||||
bool alwaysTrue = true, alwaysFalse = true;
|
bool alwaysTrue = true, alwaysFalse = true;
|
||||||
bool firstTrue = true, secondTrue = true;
|
bool firstTrue = true, secondTrue = true;
|
||||||
|
@ -684,14 +702,14 @@ void CheckCondition::checkIncorrectLogicOperator()
|
||||||
// 5 => testvalue is larger than both value1 and value2
|
// 5 => testvalue is larger than both value1 and value2
|
||||||
bool result1, result2;
|
bool result1, result2;
|
||||||
if (isfloat) {
|
if (isfloat) {
|
||||||
const double d1 = MathLib::toDoubleNumber(value1);
|
|
||||||
const double d2 = MathLib::toDoubleNumber(value2);
|
|
||||||
const double testvalue = getvalue<double>(test, d1, d2);
|
const double testvalue = getvalue<double>(test, d1, d2);
|
||||||
result1 = checkFloatRelation(op1, testvalue, d1);
|
result1 = checkFloatRelation(op1, testvalue, d1);
|
||||||
result2 = checkFloatRelation(op2, testvalue, d2);
|
result2 = checkFloatRelation(op2, testvalue, d2);
|
||||||
|
} else if (useUnsignedInt) {
|
||||||
|
const MathLib::biguint testvalue = getvalue<MathLib::biguint>(test, u1, u2);
|
||||||
|
result1 = checkIntRelation(op1, testvalue, u1);
|
||||||
|
result2 = checkIntRelation(op2, testvalue, u2);
|
||||||
} else {
|
} else {
|
||||||
const MathLib::bigint i1 = MathLib::toLongNumber(value1);
|
|
||||||
const MathLib::bigint i2 = MathLib::toLongNumber(value2);
|
|
||||||
const MathLib::bigint testvalue = getvalue<MathLib::bigint>(test, i1, i2);
|
const MathLib::bigint testvalue = getvalue<MathLib::bigint>(test, i1, i2);
|
||||||
result1 = checkIntRelation(op1, testvalue, i1);
|
result1 = checkIntRelation(op1, testvalue, i1);
|
||||||
result2 = checkIntRelation(op2, testvalue, i2);
|
result2 = checkIntRelation(op2, testvalue, i2);
|
||||||
|
|
|
@ -132,7 +132,7 @@ void TokenList::addtoken(const std::string & str, const unsigned int lineno, con
|
||||||
std::string str2;
|
std::string str2;
|
||||||
if (MathLib::isHex(str) || MathLib::isOct(str) || MathLib::isBin(str)) {
|
if (MathLib::isHex(str) || MathLib::isOct(str) || MathLib::isBin(str)) {
|
||||||
std::ostringstream str2stream;
|
std::ostringstream str2stream;
|
||||||
str2stream << MathLib::toLongNumber(str);
|
str2stream << MathLib::MathLib::toULongNumber(str);
|
||||||
str2 = str2stream.str();
|
str2 = str2stream.str();
|
||||||
} else if (str.compare(0, 5, "_Bool") == 0) {
|
} else if (str.compare(0, 5, "_Bool") == 0) {
|
||||||
str2 = "bool";
|
str2 = "bool";
|
||||||
|
|
|
@ -48,6 +48,7 @@ private:
|
||||||
TEST_CASE(incorrectLogicOperator7); // opposite expressions: (expr || !expr)
|
TEST_CASE(incorrectLogicOperator7); // opposite expressions: (expr || !expr)
|
||||||
TEST_CASE(secondAlwaysTrueFalseWhenFirstTrueError);
|
TEST_CASE(secondAlwaysTrueFalseWhenFirstTrueError);
|
||||||
TEST_CASE(incorrectLogicOp_condSwapping);
|
TEST_CASE(incorrectLogicOp_condSwapping);
|
||||||
|
TEST_CASE(testBug5895);
|
||||||
|
|
||||||
TEST_CASE(modulo);
|
TEST_CASE(modulo);
|
||||||
|
|
||||||
|
@ -656,7 +657,6 @@ private:
|
||||||
" if (x == 1.0 && x == 3.0)\n"
|
" if (x == 1.0 && x == 3.0)\n"
|
||||||
" a++;\n"
|
" a++;\n"
|
||||||
"}");
|
"}");
|
||||||
//ASSERT_EQUALS("[test.cpp:2]: (warning) Logical conjunction always evaluates to false: x == 1.0 && x == 3.0.\n", errout.str());
|
|
||||||
ASSERT_EQUALS("", errout.str()); // float comparisons with == and != are not checked right now - such comparison is a bad idea
|
ASSERT_EQUALS("", errout.str()); // float comparisons with == and != are not checked right now - such comparison is a bad idea
|
||||||
|
|
||||||
check("void f(float x) {\n"
|
check("void f(float x) {\n"
|
||||||
|
@ -1408,6 +1408,14 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testBug5895() {
|
||||||
|
check("void png_parse(uint64_t init, int buf_size) {\n"
|
||||||
|
" if (init == 0x89504e470d0a1a0a || init == 0x8a4d4e470d0a1a0a)\n"
|
||||||
|
" ;\n"
|
||||||
|
"}");
|
||||||
|
TODO_ASSERT_EQUALS("", "[test.cpp:2]: (style) Redundant condition: If init == 9894494448401390090, the comparison init == 9965707617509186058 is always true.\n", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestCondition)
|
REGISTER_TEST(TestCondition)
|
||||||
|
|
|
@ -50,6 +50,7 @@ SOURCES += $${BASEPATH}/test64bit.cpp \
|
||||||
$${BASEPATH}/testtimer.cpp \
|
$${BASEPATH}/testtimer.cpp \
|
||||||
$${BASEPATH}/testtoken.cpp \
|
$${BASEPATH}/testtoken.cpp \
|
||||||
$${BASEPATH}/testtokenize.cpp \
|
$${BASEPATH}/testtokenize.cpp \
|
||||||
|
$${BASEPATH}/testtokenlist.cpp \
|
||||||
$${BASEPATH}/testtype.cpp \
|
$${BASEPATH}/testtype.cpp \
|
||||||
$${BASEPATH}/testuninitvar.cpp \
|
$${BASEPATH}/testuninitvar.cpp \
|
||||||
$${BASEPATH}/testunusedfunctions.cpp \
|
$${BASEPATH}/testunusedfunctions.cpp \
|
||||||
|
|
Loading…
Reference in New Issue