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) {
|
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
|
// bailout: assignment
|
||||||
if (Token::Match(tok2->previous(), "!!* %name% %assign%")) {
|
else if (Token::Match(tok2->previous(), "!!* %name% %assign%")) {
|
||||||
// simplify rhs
|
// simplify rhs
|
||||||
for (Token *tok3 = tok2->tokAt(2); tok3; tok3 = tok3->next()) {
|
for (Token *tok3 = tok2->tokAt(2); tok3; tok3 = tok3->next()) {
|
||||||
if (tok3->varId() == varid) {
|
if (tok3->varId() == varid) {
|
||||||
|
|
|
@ -75,8 +75,8 @@ private:
|
||||||
TEST_CASE(valueFlowBeforeConditionTernaryOp);
|
TEST_CASE(valueFlowBeforeConditionTernaryOp);
|
||||||
|
|
||||||
TEST_CASE(valueFlowAfterAssign);
|
TEST_CASE(valueFlowAfterAssign);
|
||||||
|
|
||||||
TEST_CASE(valueFlowAfterCondition);
|
TEST_CASE(valueFlowAfterCondition);
|
||||||
|
TEST_CASE(valueFlowForwardCompoundAssign);
|
||||||
|
|
||||||
TEST_CASE(valueFlowSwitchVariable);
|
TEST_CASE(valueFlowSwitchVariable);
|
||||||
|
|
||||||
|
@ -116,6 +116,25 @@ private:
|
||||||
return false;
|
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) {
|
std::string getErrorPathForX(const char code[], unsigned int linenr) {
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
|
@ -1717,6 +1736,24 @@ private:
|
||||||
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
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() {
|
void valueFlowBitAnd() {
|
||||||
const char *code;
|
const char *code;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue