Refactoring: Expose some previously local functions to public and add Tokenizer as argument to distinguish between C and C++ code (e.g. in isSameExpression).
Refactoring: Improve type-safety for TestFixture::assertEquals to allow tests with types which were not handled correctly (e.g. unsigned long long)
This commit is contained in:
parent
e75662aaf1
commit
649a89d308
|
@ -279,13 +279,13 @@ void CheckCondition::comparisonError(const Token *tok, const std::string &bitop,
|
|||
reportError(tok, Severity::style, "comparisonError", errmsg);
|
||||
}
|
||||
|
||||
static bool isOverlappingCond(const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions)
|
||||
bool CheckCondition::isOverlappingCond(const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions) const
|
||||
{
|
||||
if (!cond1 || !cond2)
|
||||
return false;
|
||||
|
||||
// same expressions
|
||||
if (isSameExpression(cond1,cond2,constFunctions))
|
||||
if (isSameExpression(_tokenizer, cond1,cond2,constFunctions))
|
||||
return true;
|
||||
|
||||
// bitwise overlap for example 'x&7' and 'x==1'
|
||||
|
@ -308,7 +308,7 @@ static bool isOverlappingCond(const Token * const cond1, const Token * const con
|
|||
if (!num2->isNumber() || MathLib::isNegative(num2->str()))
|
||||
return false;
|
||||
|
||||
if (!isSameExpression(expr1,expr2,constFunctions))
|
||||
if (!isSameExpression(_tokenizer, expr1,expr2,constFunctions))
|
||||
return false;
|
||||
|
||||
const MathLib::bigint value1 = MathLib::toLongNumber(num1->str());
|
||||
|
@ -361,22 +361,16 @@ void CheckCondition::multiConditionError(const Token *tok, unsigned int line1)
|
|||
// Detect oppositing inner and outer conditions
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Are two conditions opposite
|
||||
* @param isNot do you want to know if cond1 is !cond2 or if cond1 and cond2 are non-overlapping. true: cond1==!cond2 false: cond1==true => cond2==false
|
||||
* @param cond1 condition1
|
||||
* @param cond2 condition2
|
||||
*/
|
||||
static bool isOppositeCond(bool isNot, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions)
|
||||
bool CheckCondition::isOppositeCond(bool isNot, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions) const
|
||||
{
|
||||
if (!cond1 || !cond2)
|
||||
return false;
|
||||
|
||||
if (cond1->str() == "!")
|
||||
return isSameExpression(cond1->astOperand1(), cond2, constFunctions);
|
||||
return isSameExpression(_tokenizer, cond1->astOperand1(), cond2, constFunctions);
|
||||
|
||||
if (cond2->str() == "!")
|
||||
return isSameExpression(cond1, cond2->astOperand1(), constFunctions);
|
||||
return isSameExpression(_tokenizer, cond1, cond2->astOperand1(), constFunctions);
|
||||
|
||||
if (!cond1->isComparisonOp() || !cond2->isComparisonOp())
|
||||
return false;
|
||||
|
@ -385,11 +379,11 @@ static bool isOppositeCond(bool isNot, const Token * const cond1, const Token *
|
|||
|
||||
// condition found .. get comparator
|
||||
std::string comp2;
|
||||
if (isSameExpression(cond1->astOperand1(), cond2->astOperand1(), constFunctions) &&
|
||||
isSameExpression(cond1->astOperand2(), cond2->astOperand2(), constFunctions)) {
|
||||
if (isSameExpression(_tokenizer, cond1->astOperand1(), cond2->astOperand1(), constFunctions) &&
|
||||
isSameExpression(_tokenizer, cond1->astOperand2(), cond2->astOperand2(), constFunctions)) {
|
||||
comp2 = cond2->str();
|
||||
} else if (isSameExpression(cond1->astOperand1(), cond2->astOperand2(), constFunctions) &&
|
||||
isSameExpression(cond1->astOperand2(), cond2->astOperand1(), constFunctions)) {
|
||||
} else if (isSameExpression(_tokenizer, cond1->astOperand1(), cond2->astOperand2(), constFunctions) &&
|
||||
isSameExpression(_tokenizer, cond1->astOperand2(), cond2->astOperand1(), constFunctions)) {
|
||||
comp2 = cond2->str();
|
||||
if (comp2[0] == '>')
|
||||
comp2[0] = '<';
|
||||
|
@ -693,9 +687,9 @@ void CheckCondition::checkIncorrectLogicOperator()
|
|||
if (!MathLib::isInt(value2) && !MathLib::isFloat(value2))
|
||||
continue;
|
||||
|
||||
if (isSameExpression(comp1, comp2, _settings->library.functionpure))
|
||||
if (isSameExpression(_tokenizer, comp1, comp2, _settings->library.functionpure))
|
||||
continue; // same expressions => only report that there are same expressions
|
||||
if (!isSameExpression(expr1, expr2, _settings->library.functionpure))
|
||||
if (!isSameExpression(_tokenizer, expr1, expr2, _settings->library.functionpure))
|
||||
continue;
|
||||
|
||||
const bool isfloat = astIsFloat(expr1, true) || MathLib::isFloat(value1) || astIsFloat(expr2, true) || MathLib::isFloat(value2);
|
||||
|
|
|
@ -95,6 +95,14 @@ public:
|
|||
|
||||
private:
|
||||
|
||||
bool isOverlappingCond(const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions) const;
|
||||
/**
|
||||
* Are two conditions opposite
|
||||
* @param isNot do you want to know if cond1 is !cond2 or if cond1 and cond2 are non-overlapping. true: cond1==!cond2 false: cond1==true => cond2==false
|
||||
* @param cond1 condition1
|
||||
* @param cond2 condition2
|
||||
*/
|
||||
bool isOppositeCond(bool isNot, const Token * const cond1, const Token * const cond2, const std::set<std::string> &constFunctions) const;
|
||||
void assignIfError(const Token *tok1, const Token *tok2, const std::string &condition, bool result);
|
||||
void mismatchingBitAndError(const Token *tok1, const MathLib::bigint num1, const Token *tok2, const MathLib::bigint num2);
|
||||
void badBitmaskCheckError(const Token *tok);
|
||||
|
|
|
@ -59,7 +59,7 @@ bool astIsFloat(const Token *tok, bool unknown)
|
|||
return unknown;
|
||||
}
|
||||
|
||||
static bool isConstExpression(const Token *tok, const std::set<std::string> &constFunctions)
|
||||
bool isConstExpression(const Token *tok, const std::set<std::string> &constFunctions)
|
||||
{
|
||||
if (!tok)
|
||||
return true;
|
||||
|
@ -77,21 +77,23 @@ static bool isConstExpression(const Token *tok, const std::set<std::string> &con
|
|||
return isConstExpression(tok->astOperand1(),constFunctions) && isConstExpression(tok->astOperand2(),constFunctions);
|
||||
}
|
||||
|
||||
bool isSameExpression(const Token *tok1, const Token *tok2, const std::set<std::string> &constFunctions)
|
||||
bool isSameExpression(const Tokenizer *tokenizer, const Token *tok1, const Token *tok2, const std::set<std::string> &constFunctions)
|
||||
{
|
||||
if (tok1 == nullptr && tok2 == nullptr)
|
||||
return true;
|
||||
if (tok1 == nullptr || tok2 == nullptr)
|
||||
return false;
|
||||
if (tok1->str() == "." && tok1->astOperand1() && tok1->astOperand1()->str() == "this")
|
||||
tok1 = tok1->astOperand2();
|
||||
if (tok2->str() == "." && tok2->astOperand1() && tok2->astOperand1()->str() == "this")
|
||||
tok2 = tok2->astOperand2();
|
||||
if (tokenizer->isCPP()) {
|
||||
if (tok1->str() == "." && tok1->astOperand1() && tok1->astOperand1()->str() == "this")
|
||||
tok1 = tok1->astOperand2();
|
||||
if (tok2->str() == "." && tok2->astOperand1() && tok2->astOperand1()->str() == "this")
|
||||
tok2 = tok2->astOperand2();
|
||||
}
|
||||
if (tok1->varId() != tok2->varId() || tok1->str() != tok2->str()) {
|
||||
if ((Token::Match(tok1,"<|>") && Token::Match(tok2,"<|>")) ||
|
||||
(Token::Match(tok1,"<=|>=") && Token::Match(tok2,"<=|>="))) {
|
||||
return isSameExpression(tok1->astOperand1(), tok2->astOperand2(), constFunctions) &&
|
||||
isSameExpression(tok1->astOperand2(), tok2->astOperand1(), constFunctions);
|
||||
return isSameExpression(tokenizer, tok1->astOperand1(), tok2->astOperand2(), constFunctions) &&
|
||||
isSameExpression(tokenizer, tok1->astOperand2(), tok2->astOperand1(), constFunctions);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -145,18 +147,18 @@ bool isSameExpression(const Token *tok1, const Token *tok2, const std::set<std::
|
|||
return false;
|
||||
}
|
||||
bool noncommuative_equals =
|
||||
isSameExpression(tok1->astOperand1(), tok2->astOperand1(), constFunctions);
|
||||
isSameExpression(tokenizer, tok1->astOperand1(), tok2->astOperand1(), constFunctions);
|
||||
noncommuative_equals = noncommuative_equals &&
|
||||
isSameExpression(tok1->astOperand2(), tok2->astOperand2(), constFunctions);
|
||||
isSameExpression(tokenizer, tok1->astOperand2(), tok2->astOperand2(), constFunctions);
|
||||
|
||||
if (noncommuative_equals)
|
||||
return true;
|
||||
|
||||
const bool commutative = tok1->astOperand1() && tok1->astOperand2() && Token::Match(tok1, "%or%|%oror%|+|*|&|&&|^|==|!=");
|
||||
bool commuative_equals = commutative &&
|
||||
isSameExpression(tok1->astOperand2(), tok2->astOperand1(), constFunctions);
|
||||
isSameExpression(tokenizer, tok1->astOperand2(), tok2->astOperand1(), constFunctions);
|
||||
commuative_equals = commuative_equals &&
|
||||
isSameExpression(tok1->astOperand1(), tok2->astOperand2(), constFunctions);
|
||||
isSameExpression(tokenizer, tok1->astOperand1(), tok2->astOperand2(), constFunctions);
|
||||
|
||||
return commuative_equals;
|
||||
}
|
||||
|
@ -195,13 +197,13 @@ void CheckOther::checkCastIntToCharAndBack()
|
|||
if (var && var->typeEndToken()->str() == "char" && !var->typeEndToken()->isSigned()) {
|
||||
checkCastIntToCharAndBackError(tok, tok->strAt(2));
|
||||
}
|
||||
} else if (Token::Match(tok, "EOF %comp% ( %var% = std :: cin . get (") || Token::Match(tok, "EOF %comp% ( %var% = cin . get (")) {
|
||||
} else if (_tokenizer->isCPP() && Token::Match(tok, "EOF %comp% ( %var% = std :: cin . get (") || Token::Match(tok, "EOF %comp% ( %var% = cin . get (")) {
|
||||
tok = tok->tokAt(3);
|
||||
const Variable *var = tok->variable();
|
||||
if (var && var->typeEndToken()->str() == "char" && !var->typeEndToken()->isSigned()) {
|
||||
checkCastIntToCharAndBackError(tok, "cin.get");
|
||||
}
|
||||
} else if (Token::Match(tok, "%var% = std :: cin . get (") || Token::Match(tok, "%var% = cin . get (")) {
|
||||
} else if (_tokenizer->isCPP() && Token::Match(tok, "%var% = std :: cin . get (") || Token::Match(tok, "%var% = cin . get (")) {
|
||||
const Variable *var = tok->variable();
|
||||
if (var && var->typeEndToken()->str() == "char" && !var->typeEndToken()->isSigned()) {
|
||||
vars[tok->varId()] = "cin.get";
|
||||
|
@ -2181,7 +2183,7 @@ namespace {
|
|||
}
|
||||
}
|
||||
|
||||
static bool isWithoutSideEffects(const Tokenizer *tokenizer, const Token* tok)
|
||||
bool isWithoutSideEffects(const Tokenizer *tokenizer, const Token* tok)
|
||||
{
|
||||
if (!tokenizer->isCPP())
|
||||
return true;
|
||||
|
@ -2217,7 +2219,7 @@ void CheckOther::checkDuplicateExpression()
|
|||
if (tok->isOp() && tok->astOperand1() && !Token::Match(tok, "+|*|<<|>>")) {
|
||||
if (Token::Match(tok, "==|!=|-") && astIsFloat(tok->astOperand1(), true))
|
||||
continue;
|
||||
if (isSameExpression(tok->astOperand1(), tok->astOperand2(), _settings->library.functionpure)) {
|
||||
if (isSameExpression(_tokenizer, tok->astOperand1(), tok->astOperand2(), _settings->library.functionpure)) {
|
||||
if (isWithoutSideEffects(_tokenizer, tok->astOperand1())) {
|
||||
const bool assignment = tok->str() == "=";
|
||||
if (assignment)
|
||||
|
@ -2236,16 +2238,16 @@ void CheckOther::checkDuplicateExpression()
|
|||
}
|
||||
}
|
||||
} else if (!Token::Match(tok, "[-/%]")) { // These operators are not associative
|
||||
if (tok->astOperand2() && tok->str() == tok->astOperand1()->str() && isSameExpression(tok->astOperand2(), tok->astOperand1()->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer, tok->astOperand2()))
|
||||
if (tok->astOperand2() && tok->str() == tok->astOperand1()->str() && isSameExpression(_tokenizer, tok->astOperand2(), tok->astOperand1()->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer, tok->astOperand2()))
|
||||
duplicateExpressionError(tok->astOperand2(), tok->astOperand2(), tok->str());
|
||||
else if (tok->astOperand2()) {
|
||||
const Token *ast1 = tok->astOperand1();
|
||||
while (ast1 && tok->str() == ast1->str()) {
|
||||
if (isSameExpression(ast1->astOperand1(), tok->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer, ast1->astOperand1()))
|
||||
if (isSameExpression(_tokenizer, ast1->astOperand1(), tok->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer, ast1->astOperand1()))
|
||||
// TODO: warn if variables are unchanged. See #5683
|
||||
// Probably the message should be changed to 'duplicate expressions X in condition or something like that'.
|
||||
;//duplicateExpressionError(ast1->astOperand1(), tok->astOperand2(), tok->str());
|
||||
else if (isSameExpression(ast1->astOperand2(), tok->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer, ast1->astOperand2()))
|
||||
else if (isSameExpression(_tokenizer, ast1->astOperand2(), tok->astOperand2(), _settings->library.functionpure) && isWithoutSideEffects(_tokenizer, ast1->astOperand2()))
|
||||
duplicateExpressionError(ast1->astOperand2(), tok->astOperand2(), tok->str());
|
||||
if (!isConstExpression(ast1->astOperand2(), _settings->library.functionpure))
|
||||
break;
|
||||
|
@ -2254,7 +2256,7 @@ void CheckOther::checkDuplicateExpression()
|
|||
}
|
||||
}
|
||||
} else if (tok->astOperand1() && tok->astOperand2() && tok->str() == ":" && tok->astParent() && tok->astParent()->str() == "?") {
|
||||
if (isSameExpression(tok->astOperand1(), tok->astOperand2(), temp))
|
||||
if (isSameExpression(_tokenizer, tok->astOperand1(), tok->astOperand2(), temp))
|
||||
duplicateExpressionTernaryError(tok);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,12 @@
|
|||
class Function;
|
||||
class Variable;
|
||||
|
||||
bool isConstExpression(const Token *tok, const std::set<std::string> &constFunctions);
|
||||
|
||||
/** Is expressions same? */
|
||||
bool isSameExpression(const Token *tok1, const Token *tok2, const std::set<std::string> &constFunctions);
|
||||
bool isSameExpression(const Tokenizer *tokenizer, const Token *tok1, const Token *tok2, const std::set<std::string> &constFunctions);
|
||||
|
||||
bool isWithoutSideEffects(const Tokenizer *tokenizer, const Token* tok);
|
||||
|
||||
/** Is expression of floating point type? */
|
||||
bool astIsFloat(const Token *tok, bool unknown);
|
||||
|
|
|
@ -366,7 +366,7 @@ private:
|
|||
|
||||
const struct Library::PodType *type = library.podtype("s16");
|
||||
ASSERT_EQUALS(2U, type ? type->size : 0U);
|
||||
ASSERT_EQUALS(0, type ? type->sign : '?');
|
||||
ASSERT_EQUALS((char)0, type ? type->sign : '?');
|
||||
}
|
||||
|
||||
void container() const {
|
||||
|
|
|
@ -264,6 +264,11 @@ private:
|
|||
ASSERT_EQUALS(-1 , MathLib::toLongNumber("-10.E-1"));
|
||||
ASSERT_EQUALS(100 , MathLib::toLongNumber("+10.0E+1"));
|
||||
ASSERT_EQUALS(-1 , MathLib::toLongNumber("-10.0E-1"));
|
||||
|
||||
ASSERT_EQUALS(-8552249625308161526, MathLib::toLongNumber("0x89504e470d0a1a0a"));
|
||||
ASSERT_EQUALS(-8481036456200365558, MathLib::toLongNumber("0x8a4d4e470d0a1a0a"));
|
||||
ASSERT_EQUALS(9894494448401390090, MathLib::toULongNumber("0x89504e470d0a1a0a"));
|
||||
ASSERT_EQUALS(9965707617509186058, MathLib::toULongNumber("0x8a4d4e470d0a1a0a"));
|
||||
|
||||
// zero input
|
||||
ASSERT_EQUALS(0 , MathLib::toULongNumber("0"));
|
||||
|
|
|
@ -129,7 +129,7 @@ void TestFixture::assert_(const char *filename, unsigned int linenr, bool condit
|
|||
}
|
||||
}
|
||||
|
||||
void TestFixture::assertEquals(const char *filename, unsigned int linenr, const std::string &expected, const std::string &actual, const std::string &msg) const
|
||||
void TestFixture::_assertEquals(const char *filename, unsigned int linenr, const std::string &expected, const std::string &actual, const std::string &msg) const
|
||||
{
|
||||
if (expected != actual) {
|
||||
++fails_counter;
|
||||
|
@ -155,23 +155,6 @@ void TestFixture::assertEquals(const char *filename, unsigned int linenr, const
|
|||
}
|
||||
}
|
||||
}
|
||||
void TestFixture::assertEquals(const char *filename, unsigned int linenr, const char expected[], const std::string& actual, const std::string &msg) const
|
||||
{
|
||||
assertEquals(filename, linenr, std::string(expected), actual, msg);
|
||||
}
|
||||
void TestFixture::assertEquals(const char *filename, unsigned int linenr, const char expected[], const char actual[], const std::string &msg) const
|
||||
{
|
||||
assertEquals(filename, linenr, std::string(expected), std::string(actual), msg);
|
||||
}
|
||||
void TestFixture::assertEquals(const char *filename, unsigned int linenr, const std::string& expected, const char actual[], const std::string &msg) const
|
||||
{
|
||||
assertEquals(filename, linenr, expected, std::string(actual), msg);
|
||||
}
|
||||
|
||||
void TestFixture::assertEquals(const char *filename, unsigned int linenr, long long expected, long long actual, const std::string &msg) const
|
||||
{
|
||||
assertEquals(filename, linenr, MathLib::toString(expected), MathLib::toString(actual), msg);
|
||||
}
|
||||
|
||||
void TestFixture::assertEqualsDouble(const char *filename, unsigned int linenr, double expected, double actual, const std::string &msg) const
|
||||
{
|
||||
|
|
|
@ -51,12 +51,36 @@ protected:
|
|||
|
||||
void assert_(const char *filename, unsigned int linenr, bool condition) const;
|
||||
void todoAssert(const char *filename, unsigned int linenr, bool condition) const;
|
||||
void _assertEquals(const char *filename, unsigned int linenr, const std::string &expected, const std::string &actual, const std::string &msg) const;
|
||||
|
||||
template <typename E, typename A>
|
||||
void assertEquals(const char *filename, unsigned int linenr, const E expected, const A actual, const std::string &msg = emptyString) const {
|
||||
_assertEquals(filename, linenr, MathLib::toString(expected), MathLib::toString(actual), msg);
|
||||
}
|
||||
|
||||
template<>
|
||||
void assertEquals(const char *filename, unsigned int linenr, const char expected[], const std::string& actual, const std::string &msg) const
|
||||
{
|
||||
assertEquals(filename, linenr, std::string(expected), actual, msg);
|
||||
}
|
||||
template<>
|
||||
void assertEquals(const char *filename, unsigned int linenr, const char expected[], const char actual[], const std::string &msg) const
|
||||
{
|
||||
assertEquals(filename, linenr, std::string(expected), std::string(actual), msg);
|
||||
}
|
||||
template<>
|
||||
void assertEquals(const char *filename, unsigned int linenr, const std::string& expected, const char actual[], const std::string &msg) const
|
||||
{
|
||||
assertEquals(filename, linenr, expected, std::string(actual), msg);
|
||||
}
|
||||
/*
|
||||
void assertEquals(const char *filename, unsigned int linenr, const std::string &expected, const std::string &actual, const std::string &msg = emptyString) const;
|
||||
void assertEquals(const char *filename, unsigned int linenr, const char expected[], const std::string& actual, const std::string &msg = emptyString) const;
|
||||
void assertEquals(const char *filename, unsigned int linenr, const char expected[], const char actual[], const std::string &msg = emptyString) const;
|
||||
void assertEquals(const char *filename, unsigned int linenr, const std::string& expected, const char actual[], const std::string &msg = emptyString) const;
|
||||
void assertEquals(const char *filename, unsigned int linenr, long long expected, long long actual, const std::string &msg = emptyString) const;
|
||||
void assertEquals(const char *filename, unsigned int linenr, unsigned long long expected, unsigned long long actual, const std::string &msg = emptyString) const;
|
||||
*/
|
||||
void assertEqualsDouble(const char *filename, unsigned int linenr, double expected, double actual, const std::string &msg = emptyString) const;
|
||||
|
||||
void todoAssertEquals(const char *filename, unsigned int linenr, const std::string &wanted,
|
||||
|
|
Loading…
Reference in New Issue