ValueFlow: Test ErrorPath handling

This commit is contained in:
Daniel Marjamäki 2017-05-19 14:34:59 +02:00
parent d96cabc7e5
commit 2bb54fef69
2 changed files with 73 additions and 24 deletions

View File

@ -2746,45 +2746,36 @@ static void valueFlowSubFunction(TokenList *tokenlist, ErrorLogger *errorLogger,
if (!functionScope)
continue;
unsigned int argnr = 0U;
for (const Token *argtok = tok->tokAt(2); argtok; argtok = argtok->nextArgument()) {
const std::vector<const Token *> &callArguments = getArguments(tok);
for (unsigned int argnr = 0U; argnr < callArguments.size(); ++argnr) {
const Token *argtok = callArguments[argnr];
// Get function argument
const Variable * const arg = currentFunction->getArgumentVar(argnr++);
if (!arg)
const Variable * const argvar = currentFunction->getArgumentVar(argnr);
if (!argvar)
break;
std::list<ValueFlow::Value> argvalues;
// passing value(s) to function
if (!argtok->values().empty() && Token::Match(argtok, "%name%|%num%|%str% [,)]"))
argvalues = argtok->values();
else {
// bool operator => values 1/0 are passed to function..
const Token *op = argtok;
while (op && op->astParent() && !Token::Match(op->astParent(), "[(,]"))
op = op->astParent();
if (Token::Match(op, "%comp%|%oror%|&&|!")) {
argvalues.clear();
std::list<ValueFlow::Value> argvalues;
if (Token::Match(argtok, "%comp%|%oror%|&&|!") && !argtok->hasKnownIntValue()) {
argvalues.push_back(ValueFlow::Value(0));
argvalues.push_back(ValueFlow::Value(1));
} else if (Token::Match(op, "%cop%") && !op->values().empty()) {
argvalues = op->values();
} else {
// possible values are unknown..
argvalues = argtok->values();
}
if (argvalues.empty())
continue;
}
}
// Error path..
for (std::list<ValueFlow::Value>::iterator it = argvalues.begin(); it != argvalues.end(); ++it)
it->errorPath.push_back(ErrorPathItem(argtok, "function call argument"));
it->errorPath.push_back(ErrorPathItem(argtok, "Function argument, integer value " + MathLib::toString(it->intvalue)));
// passed values are not "known"..
for (std::list<ValueFlow::Value>::iterator it = argvalues.begin(); it != argvalues.end(); ++it) {
it->changeKnownToPossible();
}
valueFlowInjectParameter(tokenlist, errorLogger, settings, arg, functionScope, argvalues);
valueFlowInjectParameter(tokenlist, errorLogger, settings, argvar, functionScope, argvalues);
}
}
}

View File

@ -53,6 +53,8 @@ private:
TEST_CASE(valueFlowCalculations);
TEST_CASE(valueFlowErrorPath);
TEST_CASE(valueFlowBeforeCondition);
TEST_CASE(valueFlowBeforeConditionAndAndOrOrGuard);
TEST_CASE(valueFlowBeforeConditionAssignIncDec);
@ -108,6 +110,30 @@ private:
return false;
}
std::string getErrorPathForX(const char code[], unsigned int linenr) {
// 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)
continue;
std::ostringstream ostr;
std::list<ValueFlow::Value>::const_iterator it;
for (it = tok->values().begin(); it != tok->values().end(); ++it) {
for (ValueFlow::Value::ErrorPath::const_iterator ep = it->errorPath.begin(); ep != it->errorPath.end(); ++ep) {
const Token *eptok = ep->first;
const std::string &msg = ep->second;
ostr << eptok->linenr() << ',' << msg << '\n';
}
}
return ostr.str();
}
return "";
}
bool testValueOfX(const char code[], unsigned int linenr, const char value[]) {
// Tokenize..
@ -562,6 +588,38 @@ private:
ASSERT_EQUALS(1, values.front().intvalue);
}
void valueFlowErrorPath() {
const char *code;
code = "void f() {\n"
" int x = 53;\n"
" a = x;\n"
"}\n";
ASSERT_EQUALS("2,Assignment, integer value 53\n",
getErrorPathForX(code, 3U));
code = "void f(int y) {\n"
" int x = y;\n"
" a = x;\n"
" y += 12;\n"
" if (y == 32) {}"
"}\n";
ASSERT_EQUALS("5,Condition 'y==32'\n"
"2,Assignment, integer value 20\n",
getErrorPathForX(code, 3U));
code = "void f1(int x) {\n"
" a = x;\n"
"}\n"
"void f2() {\n"
" int x = 3;\n"
" f1(x+1);\n"
"}\n";
ASSERT_EQUALS("5,Assignment, integer value 3\n"
"6,Function argument, integer value 4\n",
getErrorPathForX(code, 2U));
}
void valueFlowBeforeCondition() {
const char *code;