Fixed #1174 (improve check: Unintialized variable not detected in subfunction)
This commit is contained in:
parent
c666a9662b
commit
d3b7f5931f
|
@ -1118,6 +1118,7 @@ void CheckOther::nullPointer()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief parse a function call and extract information about variable usage
|
* \brief parse a function call and extract information about variable usage
|
||||||
* \param tok first token
|
* \param tok first token
|
||||||
|
@ -1620,7 +1621,7 @@ private:
|
||||||
if (tok.varId())
|
if (tok.varId())
|
||||||
{
|
{
|
||||||
// Used..
|
// Used..
|
||||||
if (Token::Match(tok.previous(), "[[+-*/] %var% []+-*/]"))
|
if (Token::Match(tok.previous(), "[[(,+-*/] %var% []),+-*/]"))
|
||||||
{
|
{
|
||||||
use(foundError, checks, &tok);
|
use(foundError, checks, &tok);
|
||||||
return &tok;
|
return &tok;
|
||||||
|
@ -1708,7 +1709,7 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token::Match(&tok, "%var% ("))
|
if (Token::Match(&tok, "%var% (") && uvarFunctions.find(tok.str()) == uvarFunctions.end())
|
||||||
{
|
{
|
||||||
if (Token::simpleMatch(&tok, "sizeof ("))
|
if (Token::simpleMatch(&tok, "sizeof ("))
|
||||||
return tok.next()->link();
|
return tok.next()->link();
|
||||||
|
@ -1891,8 +1892,61 @@ private:
|
||||||
|
|
||||||
return ExecutionPath::parseCondition(tok, checks);
|
return ExecutionPath::parseCondition(tok, checks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static std::set<std::string> uvarFunctions;
|
||||||
|
|
||||||
|
static void analyseFunctions(const Token * const tokens, std::set<std::string> &func)
|
||||||
|
{
|
||||||
|
for (const Token *tok = tokens; tok; tok = tok->next())
|
||||||
|
{
|
||||||
|
if (tok->str() == "{")
|
||||||
|
{
|
||||||
|
tok = tok->link();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (tok->str() != "::" && Token::Match(tok->next(), "%var% ( %type%"))
|
||||||
|
{
|
||||||
|
if (!Token::simpleMatch(tok->tokAt(2)->link(), ") {"))
|
||||||
|
continue;
|
||||||
|
const Token *tok2 = tok->tokAt(3);
|
||||||
|
while (tok2 && tok2->str() != ")")
|
||||||
|
{
|
||||||
|
if (tok2->str() == ",")
|
||||||
|
tok2 = tok2->next();
|
||||||
|
|
||||||
|
if (Token::Match(tok2, "%type% %var% ,|)") && tok2->isStandardType())
|
||||||
|
{
|
||||||
|
tok2 = tok2->tokAt(2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Token::Match(tok2, "const %type% %var% ,|)") && tok2->next()->isStandardType())
|
||||||
|
{
|
||||||
|
tok2 = tok2->tokAt(2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// found simple function..
|
||||||
|
if (tok2->link() == tok->tokAt(2))
|
||||||
|
func.insert(tok->next()->str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::set<std::string> CheckUninitVar::uvarFunctions;
|
||||||
|
|
||||||
|
|
||||||
|
void CheckOther::analyseFunctions(const Token * const tokens, std::set<std::string> &func)
|
||||||
|
{
|
||||||
|
CheckUninitVar::analyseFunctions(tokens, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void CheckOther::executionPaths()
|
void CheckOther::executionPaths()
|
||||||
|
@ -1905,6 +1959,7 @@ void CheckOther::executionPaths()
|
||||||
|
|
||||||
// check if variable is accessed uninitialized..
|
// check if variable is accessed uninitialized..
|
||||||
{
|
{
|
||||||
|
CheckUninitVar::analyseFunctions(_tokenizer->tokens(), CheckUninitVar::uvarFunctions);
|
||||||
CheckUninitVar c(this);
|
CheckUninitVar c(this);
|
||||||
checkExecutionPaths(_tokenizer->tokens(), &c);
|
checkExecutionPaths(_tokenizer->tokens(), &c);
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,11 @@ public:
|
||||||
checkOther.executionPaths();
|
checkOther.executionPaths();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO move CheckUninitVar?
|
||||||
|
static void analyseFunctions(const Token * const tokens, std::set<std::string> &func);
|
||||||
|
|
||||||
|
|
||||||
// Casting
|
// Casting
|
||||||
void warningOldStylePointerCast();
|
void warningOldStylePointerCast();
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,7 @@ private:
|
||||||
TEST_CASE(nullpointer7);
|
TEST_CASE(nullpointer7);
|
||||||
|
|
||||||
TEST_CASE(uninitvar1);
|
TEST_CASE(uninitvar1);
|
||||||
|
TEST_CASE(uninitvar_func); // analyse functions
|
||||||
|
|
||||||
TEST_CASE(oldStylePointerCast);
|
TEST_CASE(oldStylePointerCast);
|
||||||
|
|
||||||
|
@ -1668,6 +1669,39 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
|
||||||
|
// sub functions..
|
||||||
|
checkUninitVar("int foo(int x) { return x; }\n"
|
||||||
|
"void f2()\n"
|
||||||
|
"{\n"
|
||||||
|
" int x;\n"
|
||||||
|
" foo(x);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: x\n", errout.str());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string analyseFunctions(const char code[])
|
||||||
|
{
|
||||||
|
// Tokenize..
|
||||||
|
Tokenizer tokenizer;
|
||||||
|
std::istringstream istr(code);
|
||||||
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
|
||||||
|
std::set<std::string> f;
|
||||||
|
CheckOther::analyseFunctions(tokenizer.tokens(), f);
|
||||||
|
|
||||||
|
std::string ret;
|
||||||
|
for (std::set<std::string>::const_iterator it = f.begin(); it != f.end(); ++it)
|
||||||
|
ret += *it + " ";
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void uninitvar_func()
|
||||||
|
{
|
||||||
|
ASSERT_EQUALS("foo ", analyseFunctions("void foo(int x) { }"));
|
||||||
|
ASSERT_EQUALS("", analyseFunctions("void foo(s x) { }"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue