value flow: simple handling of for loops
This commit is contained in:
parent
fa04273473
commit
740f72fdbd
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue