ValueFlow: extend aftercondition analysis below conditional code
This commit is contained in:
parent
b983a8795f
commit
9999ce9468
|
@ -534,7 +534,7 @@ static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void valueFlowForward(Token * const startToken,
|
static bool valueFlowForward(Token * const startToken,
|
||||||
const Token * const endToken,
|
const Token * const endToken,
|
||||||
const Variable * const var,
|
const Variable * const var,
|
||||||
const unsigned int varid,
|
const unsigned int varid,
|
||||||
|
@ -588,13 +588,13 @@ static void valueFlowForward(Token * const startToken,
|
||||||
if (number_of_if > 0U || Token::findmatch(tok2, "%varid%", start, varid)) {
|
if (number_of_if > 0U || Token::findmatch(tok2, "%varid%", start, varid)) {
|
||||||
if (settings->debugwarnings)
|
if (settings->debugwarnings)
|
||||||
bailout(tokenlist, errorLogger, tok2, "variable " + var->nameToken()->str() + " is assigned in conditional code");
|
bailout(tokenlist, errorLogger, tok2, "variable " + var->nameToken()->str() + " is assigned in conditional code");
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (var->isStatic()) {
|
if (var->isStatic()) {
|
||||||
if (settings->debugwarnings)
|
if (settings->debugwarnings)
|
||||||
bailout(tokenlist, errorLogger, tok2, "variable " + var->nameToken()->str() + " bailout when conditional code that contains var is seen");
|
bailout(tokenlist, errorLogger, tok2, "variable " + var->nameToken()->str() + " bailout when conditional code that contains var is seen");
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove conditional values
|
// Remove conditional values
|
||||||
|
@ -609,11 +609,11 @@ static void valueFlowForward(Token * const startToken,
|
||||||
|
|
||||||
// noreturn scopes..
|
// noreturn scopes..
|
||||||
if ((number_of_if > 0 || Token::findmatch(tok2, "%varid%", start, varid)) &&
|
if ((number_of_if > 0 || Token::findmatch(tok2, "%varid%", start, varid)) &&
|
||||||
(Token::findmatch(start, "return|continue|break", end) ||
|
(Token::findmatch(start, "return|continue|break|throw", end) ||
|
||||||
(Token::simpleMatch(end,"} else {") && Token::findmatch(end, "return|continue|break", end->linkAt(2))))) {
|
(Token::simpleMatch(end,"} else {") && Token::findmatch(end, "return|continue|break|throw", end->linkAt(2))))) {
|
||||||
if (settings->debugwarnings)
|
if (settings->debugwarnings)
|
||||||
bailout(tokenlist, errorLogger, tok2, "variable " + var->nameToken()->str() + ". noreturn conditional scope.");
|
bailout(tokenlist, errorLogger, tok2, "variable " + var->nameToken()->str() + ". noreturn conditional scope.");
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isVariableChanged(start, end, varid)) {
|
if (isVariableChanged(start, end, varid)) {
|
||||||
|
@ -621,13 +621,13 @@ static void valueFlowForward(Token * const startToken,
|
||||||
Token::simpleMatch(tok2, "if (") &&
|
Token::simpleMatch(tok2, "if (") &&
|
||||||
!(Token::simpleMatch(end, "} else {") &&
|
!(Token::simpleMatch(end, "} else {") &&
|
||||||
(Token::findmatch(end, "%varid%", end->linkAt(2), varid) ||
|
(Token::findmatch(end, "%varid%", end->linkAt(2), varid) ||
|
||||||
Token::findmatch(end, "return|continue|break", end->linkAt(2))))) {
|
Token::findmatch(end, "return|continue|break|throw", end->linkAt(2))))) {
|
||||||
++number_of_if;
|
++number_of_if;
|
||||||
tok2 = end;
|
tok2 = end;
|
||||||
} else {
|
} else {
|
||||||
if (settings->debugwarnings)
|
if (settings->debugwarnings)
|
||||||
bailout(tokenlist, errorLogger, tok2, "variable " + var->nameToken()->str() + " is assigned in conditional code");
|
bailout(tokenlist, errorLogger, tok2, "variable " + var->nameToken()->str() + " is assigned in conditional code");
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -647,28 +647,28 @@ static void valueFlowForward(Token * const startToken,
|
||||||
else if (indentlevel <= 0 && Token::Match(tok2, "break|continue|goto")) {
|
else if (indentlevel <= 0 && Token::Match(tok2, "break|continue|goto")) {
|
||||||
if (settings->debugwarnings)
|
if (settings->debugwarnings)
|
||||||
bailout(tokenlist, errorLogger, tok2, "variable " + var->nameToken()->str() + ". noreturn conditional scope.");
|
bailout(tokenlist, errorLogger, tok2, "variable " + var->nameToken()->str() + ". noreturn conditional scope.");
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (indentlevel <= 0 && tok2->str() == "return")
|
else if (indentlevel <= 0 && Token::Match(tok2, "return|throw"))
|
||||||
returnStatement = true;
|
returnStatement = true;
|
||||||
|
|
||||||
else if (returnStatement && tok2->str() == ";")
|
else if (returnStatement && tok2->str() == ";")
|
||||||
break;
|
return false;
|
||||||
|
|
||||||
if (tok2->varId() == varid) {
|
if (tok2->varId() == varid) {
|
||||||
// bailout: assignment
|
// bailout: assignment
|
||||||
if (Token::Match(tok2->previous(), "!!* %var% %op%") && tok2->next()->isAssignmentOp()) {
|
if (Token::Match(tok2->previous(), "!!* %var% %op%") && tok2->next()->isAssignmentOp()) {
|
||||||
if (settings->debugwarnings)
|
if (settings->debugwarnings)
|
||||||
bailout(tokenlist, errorLogger, tok2, "assignment of " + tok2->str());
|
bailout(tokenlist, errorLogger, tok2, "assignment of " + tok2->str());
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bailout increment/decrement for now..
|
// bailout increment/decrement for now..
|
||||||
if (Token::Match(tok2->previous(), "++|-- %var%") || Token::Match(tok2, "%var% ++|--")) {
|
if (Token::Match(tok2->previous(), "++|-- %var%") || Token::Match(tok2, "%var% ++|--")) {
|
||||||
if (settings->debugwarnings)
|
if (settings->debugwarnings)
|
||||||
bailout(tokenlist, errorLogger, tok2, "increment/decrement of " + tok2->str());
|
bailout(tokenlist, errorLogger, tok2, "increment/decrement of " + tok2->str());
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bailout: possible assignment using >>
|
// bailout: possible assignment using >>
|
||||||
|
@ -679,7 +679,7 @@ static void valueFlowForward(Token * const startToken,
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
if (settings->debugwarnings)
|
if (settings->debugwarnings)
|
||||||
bailout(tokenlist, errorLogger, tok2, "Possible assignment of " + tok2->str() + " using >>");
|
bailout(tokenlist, errorLogger, tok2, "Possible assignment of " + tok2->str() + " using >>");
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -704,7 +704,7 @@ static void valueFlowForward(Token * const startToken,
|
||||||
if (bailoutFunctionPar(tok2, ValueFlow::Value(), settings, &inconclusive)) {
|
if (bailoutFunctionPar(tok2, ValueFlow::Value(), settings, &inconclusive)) {
|
||||||
if (settings->debugwarnings)
|
if (settings->debugwarnings)
|
||||||
bailout(tokenlist, errorLogger, tok2, "possible assignment of " + tok2->str() + " by subfunction");
|
bailout(tokenlist, errorLogger, tok2, "possible assignment of " + tok2->str() + " by subfunction");
|
||||||
break;
|
return false;
|
||||||
}
|
}
|
||||||
if (inconclusive) {
|
if (inconclusive) {
|
||||||
std::list<ValueFlow::Value>::iterator it;
|
std::list<ValueFlow::Value>::iterator it;
|
||||||
|
@ -713,7 +713,7 @@ static void valueFlowForward(Token * const startToken,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void valueFlowAfterAssign(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
static void valueFlowAfterAssign(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
||||||
|
@ -752,11 +752,23 @@ static void valueFlowAfterAssign(TokenList *tokenlist, ErrorLogger *errorLogger,
|
||||||
|
|
||||||
static void valueFlowAfterCondition(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
static void valueFlowAfterCondition(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
|
std::stack<const Token *> scopeEnd;
|
||||||
|
|
||||||
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||||
const Token *vartok, *numtok;
|
const Token *vartok, *numtok;
|
||||||
|
|
||||||
|
if (tok->str() == "{") {
|
||||||
|
scopeEnd.push(tok->link());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (tok->str() == "}" && !scopeEnd.empty()) {
|
||||||
|
scopeEnd.pop();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Comparison
|
// Comparison
|
||||||
if (Token::Match(tok,"==|!=|>=|<=")) {
|
else if (Token::Match(tok,"==|!=|>=|<=")) {
|
||||||
if (!tok->astOperand1() || !tok->astOperand2())
|
if (!tok->astOperand1() || !tok->astOperand2())
|
||||||
continue;
|
continue;
|
||||||
if (tok->astOperand1()->isName()) {
|
if (tok->astOperand1()->isName()) {
|
||||||
|
@ -786,7 +798,7 @@ static void valueFlowAfterCondition(TokenList *tokenlist, ErrorLogger *errorLogg
|
||||||
values.push_back(ValueFlow::Value(tok, numtok ? MathLib::toLongNumber(numtok->str()) : 0LL));
|
values.push_back(ValueFlow::Value(tok, numtok ? MathLib::toLongNumber(numtok->str()) : 0LL));
|
||||||
|
|
||||||
const Token *top = tok->astTop();
|
const Token *top = tok->astTop();
|
||||||
if (top && Token::simpleMatch(top->previous(), "if (")) {
|
if (top && Token::Match(top->previous(), "if|while (") && !top->previous()->isExpandedMacro()) {
|
||||||
// does condition reassign variable?
|
// does condition reassign variable?
|
||||||
std::stack<const Token *> tokens;
|
std::stack<const Token *> tokens;
|
||||||
tokens.push(top);
|
tokens.push(top);
|
||||||
|
@ -811,8 +823,28 @@ static void valueFlowAfterCondition(TokenList *tokenlist, ErrorLogger *errorLogg
|
||||||
startToken = top->link()->next();
|
startToken = top->link()->next();
|
||||||
else if (tok->str() == "!=" && Token::simpleMatch(top->link()->linkAt(1), "} else {"))
|
else if (tok->str() == "!=" && Token::simpleMatch(top->link()->linkAt(1), "} else {"))
|
||||||
startToken = top->link()->linkAt(1)->tokAt(2);
|
startToken = top->link()->linkAt(1)->tokAt(2);
|
||||||
|
bool ok = true;
|
||||||
if (startToken)
|
if (startToken)
|
||||||
valueFlowForward(startToken->next(), startToken->link(), var, varid, values, true, tokenlist, errorLogger, settings);
|
ok &= valueFlowForward(startToken->next(), startToken->link(), var, varid, values, true, tokenlist, errorLogger, settings);
|
||||||
|
|
||||||
|
// After conditional code..
|
||||||
|
if (ok && !scopeEnd.empty() && Token::simpleMatch(top->link(), ") {")) {
|
||||||
|
Token *after = top->link()->linkAt(1);
|
||||||
|
if (Token::simpleMatch(after->tokAt(-2), ") ; }")) {
|
||||||
|
if (settings->debugwarnings)
|
||||||
|
bailout(tokenlist, errorLogger, after, "possible noreturn scope");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (Token::simpleMatch(after, "} else {")) {
|
||||||
|
after = after->linkAt(2);
|
||||||
|
if (Token::simpleMatch(after->tokAt(-2), ") ; }")) {
|
||||||
|
if (settings->debugwarnings)
|
||||||
|
bailout(tokenlist, errorLogger, after, "possible noreturn scope");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
valueFlowForward(after->next(), scopeEnd.top(), var, varid, values, true, tokenlist, errorLogger, settings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -444,7 +444,8 @@ private:
|
||||||
" case 2: if (x==5) {} break;\n"
|
" case 2: if (x==5) {} break;\n"
|
||||||
" };\n"
|
" };\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (debug) ValueFlow bailout: variable x stopping on break\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (debug) ValueFlow bailout: variable x stopping on break\n"
|
||||||
|
"[test.cpp:4]: (debug) ValueFlow bailout: variable x. noreturn conditional scope.\n", errout.str());
|
||||||
|
|
||||||
bailout("void f(int x, int y) {\n"
|
bailout("void f(int x, int y) {\n"
|
||||||
" switch (y) {\n"
|
" switch (y) {\n"
|
||||||
|
@ -452,7 +453,8 @@ private:
|
||||||
" case 2: if (x==5) {} break;\n"
|
" case 2: if (x==5) {} break;\n"
|
||||||
" };\n"
|
" };\n"
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:3]: (debug) ValueFlow bailout: variable x stopping on return\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:3]: (debug) ValueFlow bailout: variable x stopping on return\n"
|
||||||
|
"[test.cpp:4]: (debug) ValueFlow bailout: variable x. noreturn conditional scope.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowBeforeConditionMacro() {
|
void valueFlowBeforeConditionMacro() {
|
||||||
|
@ -759,6 +761,12 @@ private:
|
||||||
"}";
|
"}";
|
||||||
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
||||||
|
|
||||||
|
// After while
|
||||||
|
code = "void f(int x) {\n"
|
||||||
|
" while (x != 3) {}\n"
|
||||||
|
" a = x;\n"
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(true, testValueOfX(code, 3U, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
void valueFlowBitAnd() {
|
void valueFlowBitAnd() {
|
||||||
|
|
Loading…
Reference in New Issue