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)
|
if (!functionScope)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
unsigned int argnr = 0U;
|
const std::vector<const Token *> &callArguments = getArguments(tok);
|
||||||
for (const Token *argtok = tok->tokAt(2); argtok; argtok = argtok->nextArgument()) {
|
for (unsigned int argnr = 0U; argnr < callArguments.size(); ++argnr) {
|
||||||
|
const Token *argtok = callArguments[argnr];
|
||||||
// Get function argument
|
// Get function argument
|
||||||
const Variable * const arg = currentFunction->getArgumentVar(argnr++);
|
const Variable * const argvar = currentFunction->getArgumentVar(argnr);
|
||||||
if (!arg)
|
if (!argvar)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
std::list<ValueFlow::Value> argvalues;
|
|
||||||
|
|
||||||
// passing value(s) to function
|
// passing value(s) to function
|
||||||
if (!argtok->values().empty() && Token::Match(argtok, "%name%|%num%|%str% [,)]"))
|
std::list<ValueFlow::Value> argvalues;
|
||||||
argvalues = argtok->values();
|
if (Token::Match(argtok, "%comp%|%oror%|&&|!") && !argtok->hasKnownIntValue()) {
|
||||||
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();
|
|
||||||
argvalues.push_back(ValueFlow::Value(0));
|
argvalues.push_back(ValueFlow::Value(0));
|
||||||
argvalues.push_back(ValueFlow::Value(1));
|
argvalues.push_back(ValueFlow::Value(1));
|
||||||
} else if (Token::Match(op, "%cop%") && !op->values().empty()) {
|
|
||||||
argvalues = op->values();
|
|
||||||
} else {
|
} else {
|
||||||
// possible values are unknown..
|
argvalues = argtok->values();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argvalues.empty())
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error path..
|
// Error path..
|
||||||
for (std::list<ValueFlow::Value>::iterator it = argvalues.begin(); it != argvalues.end(); ++it)
|
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"..
|
// passed values are not "known"..
|
||||||
for (std::list<ValueFlow::Value>::iterator it = argvalues.begin(); it != argvalues.end(); ++it) {
|
for (std::list<ValueFlow::Value>::iterator it = argvalues.begin(); it != argvalues.end(); ++it) {
|
||||||
it->changeKnownToPossible();
|
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(valueFlowCalculations);
|
||||||
|
|
||||||
|
TEST_CASE(valueFlowErrorPath);
|
||||||
|
|
||||||
TEST_CASE(valueFlowBeforeCondition);
|
TEST_CASE(valueFlowBeforeCondition);
|
||||||
TEST_CASE(valueFlowBeforeConditionAndAndOrOrGuard);
|
TEST_CASE(valueFlowBeforeConditionAndAndOrOrGuard);
|
||||||
TEST_CASE(valueFlowBeforeConditionAssignIncDec);
|
TEST_CASE(valueFlowBeforeConditionAssignIncDec);
|
||||||
|
@ -108,6 +110,30 @@ private:
|
||||||
return false;
|
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[]) {
|
bool testValueOfX(const char code[], unsigned int linenr, const char value[]) {
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
|
@ -562,6 +588,38 @@ private:
|
||||||
ASSERT_EQUALS(1, values.front().intvalue);
|
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() {
|
void valueFlowBeforeCondition() {
|
||||||
const char *code;
|
const char *code;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue