value flow: bailout in valueFlowBeforeCondition if variable can be assigned by subfunction
This commit is contained in:
parent
225001a45c
commit
85dcb14813
|
@ -44,6 +44,34 @@ static void bailout(TokenList *tokenlist, ErrorLogger *errorLogger, const Token
|
||||||
errorLogger->reportErr(errmsg);
|
errorLogger->reportErr(errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool bailoutFunctionPar(const Token *tok)
|
||||||
|
{
|
||||||
|
// passing variable to subfunction?
|
||||||
|
const bool addr = tok && Token::Match(tok->previous(), "&");
|
||||||
|
if (!tok || !Token::Match(tok->tokAt(addr?-2:-1), "[(,] &| %var% [,)]"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// goto start of function call and get argnr
|
||||||
|
unsigned int argnr = 0;
|
||||||
|
while (tok && tok->str() != "(") {
|
||||||
|
if (tok->str() == ",")
|
||||||
|
++argnr;
|
||||||
|
else if (tok->str() == ")")
|
||||||
|
tok = tok->link();
|
||||||
|
tok = tok->previous();
|
||||||
|
}
|
||||||
|
tok = tok ? tok->previous() : NULL;
|
||||||
|
if (!Token::Match(tok,"%var% ("))
|
||||||
|
return false; // not a function => dont bailout
|
||||||
|
|
||||||
|
if (!tok->function())
|
||||||
|
return true; // unknown function bailout
|
||||||
|
|
||||||
|
const Variable *arg = tok->function()->getArgumentVar(argnr);
|
||||||
|
|
||||||
|
return arg && !arg->isConst() && arg->isReference();
|
||||||
|
}
|
||||||
|
|
||||||
static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
for (Token *tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||||
|
@ -114,6 +142,13 @@ static void valueFlowBeforeCondition(TokenList *tokenlist, ErrorLogger *errorLog
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assigned by subfunction?
|
||||||
|
if (bailoutFunctionPar(tok2)) {
|
||||||
|
if (settings->debugwarnings)
|
||||||
|
bailout(tokenlist, errorLogger, tok2, "possible assignment of " + tok2->str() + " by subfunction");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// skip if variable is conditionally used in ?: expression.
|
// skip if variable is conditionally used in ?: expression.
|
||||||
const Token *parent = tok2;
|
const Token *parent = tok2;
|
||||||
while (parent && !Token::Match(parent, "%oror%|&&|?|:")) {
|
while (parent && !Token::Match(parent, "%oror%|&&|?|:")) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ private:
|
||||||
TEST_CASE(valueFlowSubFunction);
|
TEST_CASE(valueFlowSubFunction);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool testValueOfX(const char code[], unsigned int linenr, int value) {
|
bool testValueOfX(const std::string &code, unsigned int linenr, int value) {
|
||||||
Settings settings;
|
Settings settings;
|
||||||
settings.valueFlow = true; // temporary flag
|
settings.valueFlow = true; // temporary flag
|
||||||
|
|
||||||
|
@ -113,6 +113,16 @@ private:
|
||||||
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
ASSERT_EQUALS(true, testValueOfX(code, 2U, 0));
|
||||||
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
ASSERT_EQUALS(false, testValueOfX(code, 3U, 0));
|
||||||
|
|
||||||
|
// function calls
|
||||||
|
code = "void f(int x) {\n"
|
||||||
|
" a = x;\n"
|
||||||
|
" setx(x);\n"
|
||||||
|
" if (x == 1) {}\n"
|
||||||
|
"}";
|
||||||
|
ASSERT_EQUALS(true, testValueOfX(std::string("void setx(int x);")+code, 2U, 1));
|
||||||
|
ASSERT_EQUALS(false, testValueOfX(std::string("void setx(int &x);")+code, 2U, 1));
|
||||||
|
ASSERT_EQUALS(false, testValueOfX(code, 2U, 1));
|
||||||
|
|
||||||
// bailout: ?:
|
// bailout: ?:
|
||||||
bailout("void f(int x) {\n"
|
bailout("void f(int x) {\n"
|
||||||
" y = ((x<0) ? x : ((x==2)?3:4));\n"
|
" y = ((x<0) ? x : ((x==2)?3:4));\n"
|
||||||
|
|
Loading…
Reference in New Issue