ValueFlow: Test ErrorPath handling
This commit is contained in:
parent
d96cabc7e5
commit
2bb54fef69
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue