CheckIo: handle more complex variables

This commit is contained in:
Robert Reif 2013-08-23 05:35:57 +02:00 committed by Daniel Marjamäki
parent 7fc6b1344b
commit 5ce1933687
3 changed files with 52 additions and 26 deletions

View File

@ -736,28 +736,40 @@ void CheckIO::checkWrongPrintfScanfArguments()
}
}
// We can currently only check the type of arguments matching these simple patterns:
// var
// var.var
// var[...]
//
/// @todo add more complex variables, lietrals, functions, and generic expressions
// We currently only support string literals and variables.
/// @todo add non-string literals, functions, and generic expressions
bool CheckIO::getArgumentInfo(const Token * tok, const Variable **var, const Token **typeTok) const
{
if (tok && (Token::Match(tok->next(), "[,)]") ||
Token::Match(tok->next(), ". %var% [,)]") ||
(Token::simpleMatch(tok->next(), "[") && Token::Match(tok->linkAt(1)->next(), "[,)]")))) {
if (tok->next()->str() == ".")
tok = tok->tokAt(2);
if (tok) {
if (tok->type() == Token::eString) {
*var = 0;
*typeTok = 0;
return true;
} else if (tok->type() == Token::eVariable) {
const Token *varTok = 0;
for (const Token *tok1 = tok->next(); tok1; tok1 = tok1->next()) {
if (tok1->str() == "," || tok1->str() == ")") {
if (tok1->previous()->str() == "]")
varTok = tok1->linkAt(-1)->previous();
else
varTok = tok1->previous();
break;
} else if (tok1->str() == "(" || tok1->str() == "{" || tok1->str() == "[")
tok1 = tok1->link();
else if (tok1->str() == "<" && tok1->link())
tok1 = tok1->link();
else if (tok1->str() == ";")
break;
}
const Variable *variableInfo = tok->variable();
const Token *varTypeTok = variableInfo ? variableInfo->typeStartToken() : NULL;
*var = variableInfo;
*typeTok = varTypeTok;
return true;
if (varTok) {
const Variable *variableInfo = varTok->variable();
*var = variableInfo;
*typeTok = variableInfo ? variableInfo->typeStartToken() : NULL;;
return true;
}
}
}
return false;

View File

@ -9513,12 +9513,14 @@ void Tokenizer::createSymbolDatabase()
// Since it doesn't point at a fixed location it doesn't have varid
if (tok->variable() != NULL &&
tok->variable()->typeScope() &&
Token::Match(tok, "%var% [")) {
Token::Match(tok, "%var% [|.")) {
// Locate "]"
Token *tok2 = tok->next();
while (tok2 && tok2->str() == "[")
tok2 = tok2->link()->next();
// Locate "]"
if (tok->next()->str() == "[") {
while (tok2 && tok2->str() == "[")
tok2 = tok2->link()->next();
}
Token *membertok = NULL;
if (Token::Match(tok2, ". %var%"))

View File

@ -796,14 +796,26 @@ private:
check("class Foo {\n"
" double d;\n"
" struct Bar {\n"
" int i;\n"
" } bar[2];\n"
" struct Baz {\n"
" int i;\n"
" } baz;\n"
"};\n"
"int a[10];\n"
"Foo f[10];\n"
"void foo(const Foo* foo) {\n"
" printf(\"%d\", foo->d);\n"
" printf(\"%f\", a[0]);\n"
" printf(\"%d %f %f %d %f %f\",\n"
" foo->d, foo->bar[0].i, a[0],\n"
" f[0].d, f[0].baz.i, f[0].bar[0].i);\n"
"}");
ASSERT_EQUALS("[test.cpp:6]: (warning) %d in format string (no. 1) requires a signed integer given in the argument list.\n"
"[test.cpp:7]: (warning) %f in format string (no. 1) requires a floating point number given in the argument list.\n", errout.str());
ASSERT_EQUALS("[test.cpp:13]: (warning) %d in format string (no. 1) requires a signed integer given in the argument list.\n"
"[test.cpp:13]: (warning) %f in format string (no. 2) requires a floating point number given in the argument list.\n"
"[test.cpp:13]: (warning) %f in format string (no. 3) requires a floating point number given in the argument list.\n"
"[test.cpp:13]: (warning) %d in format string (no. 4) requires a signed integer given in the argument list.\n"
"[test.cpp:13]: (warning) %f in format string (no. 5) requires a floating point number given in the argument list.\n"
"[test.cpp:13]: (warning) %f in format string (no. 6) requires a floating point number given in the argument list.\n", errout.str());
}
void testPosixPrintfScanfParameterPosition() { // #4900 - No support for parameters in format strings