From 5ce1933687cf4dcc86b3c79078c724025f8c0cb6 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Fri, 23 Aug 2013 05:35:57 +0200 Subject: [PATCH] CheckIo: handle more complex variables --- lib/checkio.cpp | 48 ++++++++++++++++++++++++++++++------------------ lib/tokenize.cpp | 10 ++++++---- test/testio.cpp | 20 ++++++++++++++++---- 3 files changed, 52 insertions(+), 26 deletions(-) diff --git a/lib/checkio.cpp b/lib/checkio.cpp index f6c4eca46..69d52ff0a 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -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; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 2b52424aa..111d789e9 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -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%")) diff --git a/test/testio.cpp b/test/testio.cpp index 912dd2299..ba43c5959 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -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