value flow: simple handling of for loops

This commit is contained in:
Daniel Marjamäki 2014-01-07 19:20:56 +01:00
parent fa04273473
commit 740f72fdbd
3 changed files with 72 additions and 8 deletions

View File

@ -85,9 +85,7 @@ static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLog
continue; continue;
} }
struct ValueFlow::Value val; const ValueFlow::Value val(tok, num);
val.condition = tok;
val.intvalue = num;
for (Token *tok2 = tok->previous(); ; tok2 = tok2->previous()) { for (Token *tok2 = tok->previous(); ; tok2 = tok2->previous()) {
if (!tok2) { if (!tok2) {
@ -122,6 +120,59 @@ static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLog
} }
} }
static void valueFlowForLoop(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
{
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
if (!Token::Match(tok, "for ("))
continue;
tok = tok->tokAt(2);
if (!Token::Match(tok,"%type%| %var% = %num% ;")) { // TODO: don't use %num%
if (settings->debugwarnings)
bailout(tokenlist, errorLogger, tok, "For loop not handled");
continue;
}
Token * const vartok = tok->tokAt(Token::Match(tok, "%var% =") ? 0 : 1);
const MathLib::bigint num1 = MathLib::toLongNumber(vartok->strAt(2));
if (vartok->varId() == 0U)
continue;
tok = vartok->tokAt(4);
if (!Token::Match(tok, "%varid% <|<=|!= %num% ; %varid% ++ ) {", vartok->varId())) {
if (settings->debugwarnings)
bailout(tokenlist, errorLogger, tok, "For loop not handled");
continue;
}
const MathLib::bigint num2 = MathLib::toLongNumber(tok->strAt(2)) - ((tok->strAt(1)=="<=") ? 0 : 1);
Token * const bodyStart = tok->tokAt(7);
const Token * const bodyEnd = bodyStart->link();
// Is variable modified inside for loop
bool modified = false;
for (const Token *tok2 = bodyStart->next(); tok2 != bodyEnd; tok2 = tok2->next()) {
if (Token::Match(tok2, "%varid% =", vartok->varId())) {
modified = true;
break;
}
}
if (modified)
continue;
for (Token *tok2 = bodyStart->next(); tok2 != bodyEnd; tok2 = tok2->next()) {
if (tok2->varId() == vartok->varId()) {
tok2->values.push_back(ValueFlow::Value(num1));
tok2->values.push_back(ValueFlow::Value(num2));
}
if (tok2->str() == "{") {
if (settings->debugwarnings)
bailout(tokenlist, errorLogger, tok2, "For loop variable " + vartok->str() + " stopping on {");
break;
}
}
}
}
static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings) static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
{ {
std::list<ValueFlow::Value> argvalues; std::list<ValueFlow::Value> argvalues;
@ -129,11 +180,8 @@ static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger,
if (Token::Match(tok, "[(,] %var% [,)]") && !tok->next()->values.empty()) if (Token::Match(tok, "[(,] %var% [,)]") && !tok->next()->values.empty())
argvalues = tok->next()->values; argvalues = tok->next()->values;
else if (Token::Match(tok, "[(,] %num% [,)]")) { else if (Token::Match(tok, "[(,] %num% [,)]")) {
ValueFlow::Value val;
val.condition = 0;
val.intvalue = MathLib::toLongNumber(tok->next()->str());
argvalues.clear(); argvalues.clear();
argvalues.push_back(val); argvalues.push_back(ValueFlow::Value(MathLib::toLongNumber(tok->next()->str())));
} else { } else {
continue; continue;
} }
@ -184,6 +232,7 @@ void ValueFlow::setValues(TokenList *tokenlist, ErrorLogger *errorLogger, const
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) for (Token *tok = tokenlist->front(); tok; tok = tok->next())
tok->values.clear(); tok->values.clear();
valueFlowForLoop(tokenlist, errorLogger, settings);
valueFlowBeforeCondition(tokenlist, errorLogger, settings); valueFlowBeforeCondition(tokenlist, errorLogger, settings);
valueFlowSubFunction(tokenlist, errorLogger, settings); valueFlowSubFunction(tokenlist, errorLogger, settings);
} }

View File

@ -27,7 +27,11 @@ class ErrorLogger;
class Settings; class Settings;
namespace ValueFlow { namespace ValueFlow {
struct Value { class Value {
public:
Value() : condition(0), intvalue(0) {}
Value(long long val) : condition(0), intvalue(val) {}
Value(const Token *c, long long val) : condition(c), intvalue(val) {}
const Token *condition; const Token *condition;
long long intvalue; long long intvalue;
}; };

View File

@ -35,6 +35,7 @@ private:
void run() { void run() {
TEST_CASE(valueFlowBeforeCondition); TEST_CASE(valueFlowBeforeCondition);
TEST_CASE(valueFlowForLoop);
TEST_CASE(valueFlowSubFunction); TEST_CASE(valueFlowSubFunction);
} }
@ -104,6 +105,16 @@ private:
ASSERT_EQUALS("[test.cpp:4]: (debug) ValueFlow bailout: global variable x\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (debug) ValueFlow bailout: global variable x\n", errout.str());
} }
void valueFlowForLoop() {
const char code[] = "void f() {\n"
" for (int x = 0; x < 10; x++)\n"
" a[x] = 0;\n"
"}";
ASSERT_EQUALS(true, testValueOfX(code, 3U, 0));
ASSERT_EQUALS(true, testValueOfX(code, 3U, 9));
ASSERT_EQUALS(false, testValueOfX(code, 3U, 10));
}
void valueFlowSubFunction() { void valueFlowSubFunction() {
const char *code; const char *code;