Fixed #5916 (ValueFlow: Add a valueFlowAfterCondition() function)

This commit is contained in:
Daniel Marjamäki 2014-06-15 16:47:01 +02:00
parent d4bc643ed4
commit a27ca11b85
2 changed files with 257 additions and 165 deletions

View File

@ -534,42 +534,22 @@ static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLog
}
}
static void valueFlowAfterAssign(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
static void valueFlowForward(Token * const startToken,
const Token * const endToken,
const Variable * const var,
const unsigned int varid,
std::list<ValueFlow::Value> values,
const bool constValue,
TokenList * const tokenlist,
ErrorLogger * const errorLogger,
const Settings * const settings)
{
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
// Assignment
if ((tok->str() != "=") || (tok->astParent()))
continue;
// Lhs should be a variable
if (!tok->astOperand1() || !tok->astOperand1()->isName())
continue;
const unsigned int varid = tok->astOperand1()->varId();
if (varid == 0U)
continue;
const Variable *var = tok->astOperand1()->variable();
if (!var || !var->isLocal())
continue;
const Token * endToken = 0;
for (const Token *tok2 = var->typeStartToken(); tok2; tok2 = tok2->previous()) {
if (tok2->str() == "{") {
endToken = tok2->link();
break;
}
}
// Rhs values..
if (!tok->astOperand2() || tok->astOperand2()->values.empty())
continue;
std::list<ValueFlow::Value> values = tok->astOperand2()->values;
const bool constValue = tok->astOperand2()->isNumber();
int indentlevel = 0;
unsigned int number_of_if = 0;
int varusagelevel = -1;
bool returnStatement = false; // current statement is a return, stop analysis at the ";"
for (Token *tok2 = tok; tok2 && tok2 != endToken; tok2 = tok2->next()) {
for (Token *tok2 = startToken; tok2 && tok2 != endToken; tok2 = tok2->next()) {
if (indentlevel >= 0 && tok2->str() == "{")
++indentlevel;
else if (indentlevel >= 0 && tok2->str() == "}")
@ -733,6 +713,81 @@ static void valueFlowAfterAssign(TokenList *tokenlist, ErrorLogger *errorLogger,
}
}
}
}
static void valueFlowAfterAssign(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
{
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
// Assignment
if ((tok->str() != "=") || (tok->astParent()))
continue;
// Lhs should be a variable
if (!tok->astOperand1() || !tok->astOperand1()->isName())
continue;
const unsigned int varid = tok->astOperand1()->varId();
if (varid == 0U)
continue;
const Variable *var = tok->astOperand1()->variable();
if (!var || !var->isLocal())
continue;
const Token * endToken = 0;
for (const Token *tok2 = var->typeStartToken(); tok2; tok2 = tok2->previous()) {
if (tok2->str() == "{") {
endToken = tok2->link();
break;
}
}
// Rhs values..
if (!tok->astOperand2() || tok->astOperand2()->values.empty())
continue;
std::list<ValueFlow::Value> values = tok->astOperand2()->values;
const bool constValue = tok->astOperand2()->isNumber();
valueFlowForward(tok, endToken, var, varid, values, constValue, tokenlist, errorLogger, settings);
}
}
static void valueFlowAfterCondition(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
{
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
// Comparison
if (!tok->isComparisonOp() || !Token::Match(tok,"==|!=|>=|<="))
continue;
if (!tok->astOperand1() || !tok->astOperand2())
continue;
const Token *vartok, *numtok;
if (tok->astOperand1()->isName()) {
vartok = tok->astOperand1();
numtok = tok->astOperand2();
} else {
vartok = tok->astOperand2();
numtok = tok->astOperand1();
}
if (!vartok->isName() || !numtok->isNumber())
continue;
const unsigned int varid = vartok->varId();
if (varid == 0U)
continue;
const Variable *var = vartok->variable();
if (!var || !(var->isLocal() || var->isArgument()))
continue;
std::list<ValueFlow::Value> values = numtok->values;
const Token *top = tok->astTop();
if (top && Token::simpleMatch(top->previous(), "if (")) {
Token *startToken = nullptr;
if (Token::Match(tok, "==|>=|<=") && Token::simpleMatch(top->link(), ") {"))
startToken = top->link()->next();
else if (tok->str() == "!=" && Token::simpleMatch(top->link()->linkAt(1), "} else {"))
startToken = top->link()->linkAt(1)->tokAt(2);
if (startToken)
valueFlowForward(startToken->next(), startToken->link(), var, varid, values, true, tokenlist, errorLogger, settings);
}
}
}
@ -1080,5 +1135,6 @@ void ValueFlow::setValues(TokenList *tokenlist, ErrorLogger *errorLogger, const
valueFlowForLoop(tokenlist, errorLogger, settings);
valueFlowBeforeCondition(tokenlist, errorLogger, settings);
valueFlowAfterAssign(tokenlist, errorLogger, settings);
valueFlowAfterCondition(tokenlist, errorLogger, settings);
valueFlowSubFunction(tokenlist, errorLogger, settings);
}

View File

@ -55,6 +55,8 @@ private:
TEST_CASE(valueFlowAfterAssign);
TEST_CASE(valueFlowAfterCondition);
TEST_CASE(valueFlowForLoop);
TEST_CASE(valueFlowSubFunction);
}
@ -470,7 +472,9 @@ private:
"out:"
" if (x==123){}\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (debug) ValueFlow bailout: variable x stopping on goto label\n", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (debug) ValueFlow bailout: variable x stopping on goto label\n"
"[test.cpp:2]: (debug) ValueFlow bailout: variable x. noreturn conditional scope.\n"
, errout.str());
// #5721 - FP
bailout("static void f(int rc) {\n"
@ -716,6 +720,38 @@ private:
ASSERT_EQUALS(false, testValueOfX(code, 8U, 2)); // x is not 2 at line 8
}
void valueFlowAfterCondition() {
const char *code;
// if
code = "void f(int x) {\n"
" if (x == 123) {\n"
" a = x;\n"
" }\n"
"}";
ASSERT_EQUALS(true, testValueOfX(code, 3U, 123));
code = "void f(int x) {\n"
" if (x != 123) {\n"
" a = x;\n"
" }\n"
"}";
ASSERT_EQUALS(false, testValueOfX(code, 3U, 123));
// else
code = "void f(int x) {\n"
" if (x == 123) {}\n"
" else a = x;\n"
"}";
ASSERT_EQUALS(false, testValueOfX(code, 3U, 123));
code = "void f(int x) {\n"
" if (x != 123) {}\n"
" else a = x;\n"
"}";
ASSERT_EQUALS(true, testValueOfX(code, 3U, 123));
}
void valueFlowBitAnd() {
const char *code;