valueFlowForward: improve handling of compound assignments
This commit is contained in:
parent
71b0370389
commit
167cfb1ac5
|
@ -1672,8 +1672,66 @@ static bool valueFlowForward(Token * const startToken,
|
|||
}
|
||||
|
||||
else if (tok2->varId() == varid) {
|
||||
// compound assignment, known value in rhs
|
||||
if (Token::Match(tok2->previous(), "!!* %name% %assign%") &&
|
||||
tok2->next()->str() != "=" &&
|
||||
tok2->next()->astOperand2() &&
|
||||
tok2->next()->astOperand2()->hasKnownIntValue()) {
|
||||
|
||||
const ValueFlow::Value &rhsValue = tok2->next()->astOperand2()->values().front();
|
||||
const std::string &assign = tok2->next()->str();
|
||||
std::list<ValueFlow::Value>::iterator it;
|
||||
// Erase values that are not int values..
|
||||
for (it = values.begin(); it != values.end();) {
|
||||
if (it->isIntValue()) {
|
||||
if (assign == "+=")
|
||||
it->intvalue += rhsValue.intvalue;
|
||||
else if (assign == "-=")
|
||||
it->intvalue -= rhsValue.intvalue;
|
||||
else if (assign == "*=")
|
||||
it->intvalue *= rhsValue.intvalue;
|
||||
else if (assign == "/=")
|
||||
it->intvalue /= rhsValue.intvalue;
|
||||
else if (assign == "%=")
|
||||
it->intvalue %= rhsValue.intvalue;
|
||||
else if (assign == "&=")
|
||||
it->intvalue &= rhsValue.intvalue;
|
||||
else if (assign == "|=")
|
||||
it->intvalue |= rhsValue.intvalue;
|
||||
else if (assign == "^=")
|
||||
it->intvalue ^= rhsValue.intvalue;
|
||||
else {
|
||||
values.clear();
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
} else if (it->isFloatValue()) {
|
||||
if (assign == "+=")
|
||||
it->floatValue += rhsValue.intvalue;
|
||||
else if (assign == "-=")
|
||||
it->floatValue -= rhsValue.intvalue;
|
||||
else if (assign == "*=")
|
||||
it->floatValue *= rhsValue.intvalue;
|
||||
else if (assign == "/=")
|
||||
it->floatValue /= rhsValue.intvalue;
|
||||
else {
|
||||
values.clear();
|
||||
break;
|
||||
}
|
||||
++it;
|
||||
} else {
|
||||
it = values.erase(it);
|
||||
}
|
||||
}
|
||||
if (values.empty()) {
|
||||
if (settings->debugwarnings)
|
||||
bailout(tokenlist, errorLogger, tok2, "coumpound assignment of " + tok2->str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// bailout: assignment
|
||||
if (Token::Match(tok2->previous(), "!!* %name% %assign%")) {
|
||||
else if (Token::Match(tok2->previous(), "!!* %name% %assign%")) {
|
||||
// simplify rhs
|
||||
for (Token *tok3 = tok2->tokAt(2); tok3; tok3 = tok3->next()) {
|
||||
if (tok3->varId() == varid) {
|
||||
|
|
|
@ -75,8 +75,8 @@ private:
|
|||
TEST_CASE(valueFlowBeforeConditionTernaryOp);
|
||||
|
||||
TEST_CASE(valueFlowAfterAssign);
|
||||
|
||||
TEST_CASE(valueFlowAfterCondition);
|
||||
TEST_CASE(valueFlowForwardCompoundAssign);
|
||||
|
||||
TEST_CASE(valueFlowSwitchVariable);
|
||||
|
||||
|
@ -116,6 +116,25 @@ private:
|
|||
return false;
|
||||
}
|
||||
|
||||
bool testValueOfX(const char code[], unsigned int linenr, float value, float diff) {
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer(&settings, this);
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, "test.cpp");
|
||||
|
||||
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
|
||||
if (tok->str() == "x" && tok->linenr() == linenr) {
|
||||
std::list<ValueFlow::Value>::const_iterator it;
|
||||
for (it = tok->values().begin(); it != tok->values().end(); ++it) {
|
||||
if (it->isFloatValue() && it->floatValue >= value - diff && it->floatValue <= value + diff)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string getErrorPathForX(const char code[], unsigned int linenr) {
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer(&settings, this);
|
||||
|
@ -1717,6 +1736,24 @@ private:
|
|||
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
||||
}
|
||||
|
||||
void valueFlowForwardCompoundAssign() {
|
||||
const char *code;
|
||||
|
||||
code = "void f() {\n"
|
||||
" int x = 123;\n"
|
||||
" x += 43;\n"
|
||||
" return x;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 4U, 166));
|
||||
|
||||
code = "void f() {\n"
|
||||
" float x = 123.45;\n"
|
||||
" x += 67;\n"
|
||||
" return x;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(true, testValueOfX(code, 4U, 123.45 + 67, 0.01));
|
||||
}
|
||||
|
||||
void valueFlowBitAnd() {
|
||||
const char *code;
|
||||
|
||||
|
|
Loading…
Reference in New Issue