ValueFlow: Set values in else branch even when the first branch modifies the value (#1309)
* Set values in else branch even when the first branch modifies the value * Move tests * Add check for goto * Remvoe todo * Also check scope is noreturn * Use isEscapeScope when variables are changed
This commit is contained in:
parent
01ceb9bae7
commit
f093692551
|
@ -1543,6 +1543,14 @@ static bool evalAssignment(ValueFlow::Value &lhsValue, const std::string &assign
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isEscapeScope(const Token* tok, TokenList * tokenlist)
|
||||||
|
{
|
||||||
|
if(!Token::simpleMatch(tok, "{"))
|
||||||
|
return false;
|
||||||
|
return Token::findmatch(tok, "return|continue|break|throw|goto", tok->link()) ||
|
||||||
|
(tokenlist && tokenlist->getSettings()->library.isScopeNoReturn(tok->link(), nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
static bool 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,
|
||||||
|
@ -1848,8 +1856,8 @@ static bool 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|throw", end) ||
|
(isEscapeScope(start, tokenlist) ||
|
||||||
(Token::simpleMatch(end,"} else {") && Token::findmatch(end, "return|continue|break|throw", end->linkAt(2))))) {
|
(Token::simpleMatch(end,"} else {") && isEscapeScope(end->tokAt(2), tokenlist)))) {
|
||||||
if (settings->debugwarnings)
|
if (settings->debugwarnings)
|
||||||
bailout(tokenlist, errorLogger, tok2, "variable " + var->name() + ". noreturn conditional scope.");
|
bailout(tokenlist, errorLogger, tok2, "variable " + var->name() + ". noreturn conditional scope.");
|
||||||
return false;
|
return false;
|
||||||
|
@ -1859,8 +1867,7 @@ static bool valueFlowForward(Token * const startToken,
|
||||||
if ((!read || number_of_if == 0) &&
|
if ((!read || number_of_if == 0) &&
|
||||||
Token::simpleMatch(tok2, "if (") &&
|
Token::simpleMatch(tok2, "if (") &&
|
||||||
!(Token::simpleMatch(end, "} else {") &&
|
!(Token::simpleMatch(end, "} else {") &&
|
||||||
(Token::findmatch(end, "%varid%", end->linkAt(2), varid) ||
|
isEscapeScope(end->tokAt(2), tokenlist))) {
|
||||||
Token::findmatch(end, "return|continue|break|throw", end->linkAt(2))))) {
|
|
||||||
++number_of_if;
|
++number_of_if;
|
||||||
tok2 = end;
|
tok2 = end;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1583,6 +1583,23 @@ private:
|
||||||
"}";
|
"}";
|
||||||
ASSERT_EQUALS(false, testValueOfX(code, 9U, 0));
|
ASSERT_EQUALS(false, testValueOfX(code, 9U, 0));
|
||||||
|
|
||||||
|
code = "void f(int i) {\n"
|
||||||
|
" bool x = false;\n"
|
||||||
|
" if (i == 0) { x = true; }\n"
|
||||||
|
" else if (x && i == 1) {}\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(true, testValueOfX(code, 4U, 0));
|
||||||
|
|
||||||
|
code = "void f(int i) {\n"
|
||||||
|
" bool x = false;\n"
|
||||||
|
" while(i > 0) {\n"
|
||||||
|
" i++;\n"
|
||||||
|
" if (i == 0) { x = true; }\n"
|
||||||
|
" else if (x && i == 1) {}\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n";
|
||||||
|
ASSERT_EQUALS(false, testValueOfX(code, 6U, 0));
|
||||||
|
|
||||||
// multivariables
|
// multivariables
|
||||||
code = "void f(int a) {\n"
|
code = "void f(int a) {\n"
|
||||||
" int x = a;\n"
|
" int x = a;\n"
|
||||||
|
@ -3137,6 +3154,53 @@ private:
|
||||||
"}";
|
"}";
|
||||||
values = tokenValues(code, "x ; }");
|
values = tokenValues(code, "x ; }");
|
||||||
ASSERT_EQUALS(true, values.empty());
|
ASSERT_EQUALS(true, values.empty());
|
||||||
|
|
||||||
|
code = "void b(bool d, bool e) {\n"
|
||||||
|
" int c;\n"
|
||||||
|
" if (d)\n"
|
||||||
|
" c = 0;\n"
|
||||||
|
" if (e)\n"
|
||||||
|
" goto;\n"
|
||||||
|
" c++;\n"
|
||||||
|
"}\n";
|
||||||
|
values = tokenValues(code, "c ++ ; }");
|
||||||
|
ASSERT_EQUALS(true, values.empty());
|
||||||
|
|
||||||
|
code = "void b(bool d, bool e) {\n"
|
||||||
|
" int c;\n"
|
||||||
|
" if (d)\n"
|
||||||
|
" c = 0;\n"
|
||||||
|
" if (e)\n"
|
||||||
|
" return;\n"
|
||||||
|
" c++;\n"
|
||||||
|
"}\n";
|
||||||
|
values = tokenValues(code, "c ++ ; }");
|
||||||
|
ASSERT_EQUALS(true, values.empty());
|
||||||
|
|
||||||
|
code = "void b(bool d, bool e) {\n"
|
||||||
|
" int c;\n"
|
||||||
|
" if (d)\n"
|
||||||
|
" c = 0;\n"
|
||||||
|
" if (e)\n"
|
||||||
|
" exit();\n"
|
||||||
|
" c++;\n"
|
||||||
|
"}\n";
|
||||||
|
values = tokenValues(code, "c ++ ; }");
|
||||||
|
ASSERT_EQUALS(true, values.empty());
|
||||||
|
|
||||||
|
code = "void b(bool d, bool e) {\n"
|
||||||
|
" int c;\n"
|
||||||
|
" if (d)\n"
|
||||||
|
" c = 0;\n"
|
||||||
|
" else if (!d)\n"
|
||||||
|
" c = 0;\n"
|
||||||
|
" c++;\n"
|
||||||
|
"}\n";
|
||||||
|
values = tokenValues(code, "c ++ ; }");
|
||||||
|
ASSERT_EQUALS(true, values.size() == 2);
|
||||||
|
ASSERT_EQUALS(true, values.front().isUninitValue() || values.back().isUninitValue());
|
||||||
|
ASSERT_EQUALS(true, values.front().isPossible() || values.back().isPossible());
|
||||||
|
ASSERT_EQUALS(true, values.front().intvalue == 0 || values.back().intvalue == 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue