From a1b9bb0688529278948097a0d2eddc5acda5614d Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Mon, 26 Aug 2013 06:03:26 +0200 Subject: [PATCH] CheckIO: Fix false positives for functions returning unknown types and false negatives for functions returning record types --- lib/checkio.cpp | 10 +-- lib/symboldatabase.cpp | 21 ++++- lib/symboldatabase.h | 4 +- lib/tokenize.cpp | 24 +++++ test/testio.cpp | 198 +++++++++++++++++++++++++++-------------- 5 files changed, 180 insertions(+), 77 deletions(-) diff --git a/lib/checkio.cpp b/lib/checkio.cpp index 22290af84..50d74bf99 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -594,7 +594,7 @@ void CheckIO::checkWrongPrintfScanfArguments() case 'X': case 'o': specifier += *i; - if (functionInfo && varTypeTok && (varTypeTok->isStandardType() || !Token::Match(varTypeTok->next(), "*|&"))) { + if (functionInfo && varTypeTok && ((varTypeTok->isStandardType() || functionInfo->retType) && varTypeTok->next()->str() != "*")) { if (!Token::Match(varTypeTok, "bool|short|long|int|char|size_t") || (specifier[0] == 'l' && (varTypeTok->str() != "long" || (specifier[1] == 'l' && !varTypeTok->isLong())))) { invalidPrintfArgTypeError_int(tok, numFormat, specifier); @@ -612,7 +612,7 @@ void CheckIO::checkWrongPrintfScanfArguments() case 'd': case 'i': specifier += *i; - if (functionInfo && varTypeTok && (varTypeTok->isStandardType() || Token::Match(varTypeTok->next(), "*|&"))) { + if (functionInfo && varTypeTok && (varTypeTok->isStandardType() || functionInfo->retType) && varTypeTok->next()->str() != "*") { if (((varTypeTok->isUnsigned() || !Token::Match(varTypeTok, "bool|short|long|int")) && varTypeTok->str() != "char") || (specifier[0] == 'l' && (varTypeTok->str() != "long" || (specifier[1] == 'l' && !varTypeTok->isLong())))) { invalidPrintfArgTypeError_sint(tok, numFormat, specifier); @@ -629,7 +629,7 @@ void CheckIO::checkWrongPrintfScanfArguments() break; case 'u': specifier += *i; - if (functionInfo && varTypeTok && (varTypeTok->isStandardType() || !Token::Match(varTypeTok->next(), "*|&"))) { + if (functionInfo && varTypeTok && ((varTypeTok->isStandardType() || functionInfo->retType) || varTypeTok->next()->str() != "*")) { if (((!varTypeTok->isUnsigned() || !Token::Match(varTypeTok, "char|short|long|int|size_t")) && varTypeTok->str() != "bool") || (specifier[0] == 'l' && (varTypeTok->str() != "long" || (specifier[1] == 'l' && !varTypeTok->isLong())))) { invalidPrintfArgTypeError_uint(tok, numFormat, specifier); @@ -659,8 +659,8 @@ void CheckIO::checkWrongPrintfScanfArguments() case 'g': case 'G': specifier += *i; - if (functionInfo && varTypeTok && ((varTypeTok->isStandardType() && !Token::Match(varTypeTok, "float|double")) || - Token::Match(varTypeTok->next(), "*|&") || + if (functionInfo && varTypeTok && (((varTypeTok->isStandardType() || functionInfo->retType) && !Token::Match(varTypeTok, "float|double")) || + Token::simpleMatch(varTypeTok->next(), "*") || (specifier[0] == 'l' && (!varTypeTok->isLong() || varTypeTok->str() != "double")) || (specifier[0] != 'l' && varTypeTok->isLong()))) invalidPrintfArgTypeError_float(tok, numFormat, specifier); diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 878417955..24e523951 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -423,7 +423,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti // find the return type if (function.type != Function::eConstructor) { - while (tok1 && Token::Match(tok1->next(), "virtual|static|friend|const")) + while (tok1 && Token::Match(tok1->next(), "virtual|static|friend|const|struct|union")) tok1 = tok1->next(); if (tok1) @@ -741,6 +741,22 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti classAndStructScopes.push_back(&*it); } + // fill in function return types + for (std::list::iterator it = scopeList.begin(); it != scopeList.end(); ++it) { + std::list::iterator func; + + for (func = it->functionList.begin(); func != it->functionList.end(); ++func) { + // add return types + if (func->retDef) { + const Token *type = func->retDef; + while (Token::Match(type, "static|const|struct|union")) + type = type->next(); + if (type) + func->retType = findTypeInNested(type, func->nestedIn); + } + } + } + // determine if user defined type needs initialization unsigned int unknowns = 0; // stop checking when there are no unknowns unsigned int retry = 0; // bail if we don't resolve all the variable types for some reason @@ -1725,9 +1741,10 @@ void SymbolDatabase::printOut(const char *title) const std::cout << " isDelete: " << (func->isDelete ? "true" : "false") << std::endl; std::cout << " isOperator: " << (func->isOperator ? "true" : "false") << std::endl; std::cout << " retFuncPtr: " << (func->retFuncPtr ? "true" : "false") << std::endl; - std::cout << " tokenDef: " << _tokenizer->list.fileLine(func->tokenDef) << std::endl; + std::cout << " tokenDef: " << func->tokenDef->str() << " " <<_tokenizer->list.fileLine(func->tokenDef) << std::endl; std::cout << " argDef: " << _tokenizer->list.fileLine(func->argDef) << std::endl; std::cout << " retDef: " << func->retDef->str() << " " <<_tokenizer->list.fileLine(func->retDef) << std::endl; + std::cout << " retType: " << func->retType << std::endl; if (func->hasBody) { std::cout << " token: " << _tokenizer->list.fileLine(func->token) << std::endl; std::cout << " arg: " << _tokenizer->list.fileLine(func->arg) << std::endl; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 4b637195b..4bf236910 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -451,6 +451,7 @@ public: token(NULL), arg(NULL), retDef(NULL), + retType(NULL), functionScope(NULL), nestedIn(NULL), initArgCount(0), @@ -502,7 +503,8 @@ public: const Token *argDef; // function argument start '(' in class definition const Token *token; // function name token in implementation const Token *arg; // function argument start '(' - const Token *retDef; + const Token *retDef; // function return type token + const ::Type *retType; // function return type const Scope *functionScope; // scope of function body const Scope* nestedIn; // Scope the function is declared in std::list argumentList; // argument list diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 51f49904b..2bda092a0 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9540,6 +9540,30 @@ void Tokenizer::createSymbolDatabase() membertok->variable(membervar); } } + + // check for function returning record type + // func(...).var + // func(...)[...].var + else if (tok->function() && tok->next()->str() == "(" && + (Token::Match(tok->next()->link(), ") . %var% !!(") || + (Token::Match(tok->next()->link(), ") [") && Token::Match(tok->next()->link()->next()->link(), "] . %var% !!(")))) { + const Type *type = tok->function()->retType; + if (type) { + Token *membertok; + if (tok->next()->link()->next()->str() == ".") + membertok = tok->next()->link()->next()->next(); + else + membertok = tok->next()->link()->next()->link()->next()->next(); + const Variable *membervar = membertok->variable(); + if (!membervar) { + if (type->classScope) { + membervar = type->classScope->getVariable(membertok->str()); + if (membervar) + membertok->variable(membervar); + } + } + } + } } } } diff --git a/test/testio.cpp b/test/testio.cpp index e63453a18..d28945a37 100644 --- a/test/testio.cpp +++ b/test/testio.cpp @@ -861,93 +861,93 @@ private: "[test.cpp:2]: (warning) %p in format string (no. 5) requires an address given in the argument list.\n", errout.str()); check("int f() { return 0; }\n" - "void foo() { printf(\"%u %lu %f %lf %p\", f(), f(), f(), f(), f()); }"); - ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 1) requires an unsigned integer given in the argument list.\n" - "[test.cpp:2]: (warning) %lu in format string (no. 2) requires an unsigned long integer given in the argument list.\n" - "[test.cpp:2]: (warning) %f in format string (no. 3) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %lf in format string (no. 4) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %p in format string (no. 5) requires an address given in the argument list.\n", errout.str()); + "void foo() { printf(\"%d %u %lu %f %lf %p\", f(), f(), f(), f(), f(), f()); }"); + ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 2) requires an unsigned integer given in the argument list.\n" + "[test.cpp:2]: (warning) %lu in format string (no. 3) requires an unsigned long integer given in the argument list.\n" + "[test.cpp:2]: (warning) %f in format string (no. 4) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %lf in format string (no. 5) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %p in format string (no. 6) requires an address given in the argument list.\n", errout.str()); check("unsigned int f() { return 0; }\n" - "void foo() { printf(\"%d %ld %f %lf %p\", f(), f(), f(), f(), f()); }"); - ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 1) requires a signed integer given in the argument list.\n" - "[test.cpp:2]: (warning) %ld in format string (no. 2) requires a signed long integer given in the argument list.\n" - "[test.cpp:2]: (warning) %f in format string (no. 3) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %lf in format string (no. 4) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %p in format string (no. 5) requires an address given in the argument list.\n", errout.str()); + "void foo() { printf(\"%u %d %ld %f %lf %p\", f(), f(), f(), f(), f(), f()); }"); + ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires a signed integer given in the argument list.\n" + "[test.cpp:2]: (warning) %ld in format string (no. 3) requires a signed long integer given in the argument list.\n" + "[test.cpp:2]: (warning) %f in format string (no. 4) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %lf in format string (no. 5) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %p in format string (no. 6) requires an address given in the argument list.\n", errout.str()); check("long f() { return 0; }\n" - "void foo() { printf(\"%u %f %lf %p\", f(), f(), f(), f()); }"); - ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 1) requires an unsigned integer given in the argument list.\n" - "[test.cpp:2]: (warning) %f in format string (no. 2) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %lf in format string (no. 3) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %p in format string (no. 4) requires an address given in the argument list.\n", errout.str()); + "void foo() { printf(\"%ld %u %f %lf %p\", f(), f(), f(), f(), f()); }"); + ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 2) requires an unsigned integer given in the argument list.\n" + "[test.cpp:2]: (warning) %f in format string (no. 3) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %lf in format string (no. 4) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %p in format string (no. 5) requires an address given in the argument list.\n", errout.str()); check("unsigned long f() { return 0; }\n" - "void foo() { printf(\"%d %f %lf %p\", f(), f(), f(), f()); }"); - ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 1) requires a signed integer given in the argument list.\n" - "[test.cpp:2]: (warning) %f in format string (no. 2) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %lf in format string (no. 3) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %p in format string (no. 4) requires an address given in the argument list.\n", errout.str()); + "void foo() { printf(\"%lu %d %f %lf %p\", f(), f(), f(), f(), f()); }"); + ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires a signed integer given in the argument list.\n" + "[test.cpp:2]: (warning) %f in format string (no. 3) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %lf in format string (no. 4) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %p in format string (no. 5) requires an address given in the argument list.\n", errout.str()); check("float f() { return 0; }\n" - "void foo() { printf(\"%d %ld %u %lu %lf %p\", f(), f(), f(), f(), f(), f()); }"); - ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 1) requires a signed integer given in the argument list.\n" - "[test.cpp:2]: (warning) %ld in format string (no. 2) requires a signed long integer given in the argument list.\n" - "[test.cpp:2]: (warning) %u in format string (no. 3) requires an unsigned integer given in the argument list.\n" - "[test.cpp:2]: (warning) %lu in format string (no. 4) requires an unsigned long integer given in the argument list.\n" - "[test.cpp:2]: (warning) %lf in format string (no. 5) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %p in format string (no. 6) requires an address given in the argument list.\n", errout.str()); + "void foo() { printf(\"%f %d %ld %u %lu %lf %p\", f(), f(), f(), f(), f(), f(), f()); }"); + ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires a signed integer given in the argument list.\n" + "[test.cpp:2]: (warning) %ld in format string (no. 3) requires a signed long integer given in the argument list.\n" + "[test.cpp:2]: (warning) %u in format string (no. 4) requires an unsigned integer given in the argument list.\n" + "[test.cpp:2]: (warning) %lu in format string (no. 5) requires an unsigned long integer given in the argument list.\n" + "[test.cpp:2]: (warning) %lf in format string (no. 6) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %p in format string (no. 7) requires an address given in the argument list.\n", errout.str()); check("double f() { return 0; }\n" - "void foo() { printf(\"%d %ld %u %lu %lf %p\", f(), f(), f(), f(), f(), f()); }"); - ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 1) requires a signed integer given in the argument list.\n" - "[test.cpp:2]: (warning) %ld in format string (no. 2) requires a signed long integer given in the argument list.\n" - "[test.cpp:2]: (warning) %u in format string (no. 3) requires an unsigned integer given in the argument list.\n" - "[test.cpp:2]: (warning) %lu in format string (no. 4) requires an unsigned long integer given in the argument list.\n" + "void foo() { printf(\"%f %d %ld %u %lu %lf %p\", f(), f(), f(), f(), f(), f(), f()); }"); + ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires a signed integer given in the argument list.\n" + "[test.cpp:2]: (warning) %ld in format string (no. 3) requires a signed long integer given in the argument list.\n" + "[test.cpp:2]: (warning) %u in format string (no. 4) requires an unsigned integer given in the argument list.\n" + "[test.cpp:2]: (warning) %lu in format string (no. 5) requires an unsigned long integer given in the argument list.\n" + "[test.cpp:2]: (warning) %lf in format string (no. 6) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %p in format string (no. 7) requires an address given in the argument list.\n", errout.str()); + + check("long double f() { return 0; }\n" + "void foo() { printf(\"%lf %d %ld %u %lu %f %p\", f(), f(), f(), f(), f(), f(), f()); }"); + ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires a signed integer given in the argument list.\n" + "[test.cpp:2]: (warning) %ld in format string (no. 3) requires a signed long integer given in the argument list.\n" + "[test.cpp:2]: (warning) %u in format string (no. 4) requires an unsigned integer given in the argument list.\n" + "[test.cpp:2]: (warning) %lu in format string (no. 5) requires an unsigned long integer given in the argument list.\n" + "[test.cpp:2]: (warning) %f in format string (no. 6) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %p in format string (no. 7) requires an address given in the argument list.\n", errout.str()); + + check("namespace bar { int f() { return 0; } }\n" + "void foo() { printf(\"%d %u %lu %f %lf %p\", bar::f(), bar::f(), bar::f(), bar::f(), bar::f(), bar::f()); }"); + ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 2) requires an unsigned integer given in the argument list.\n" + "[test.cpp:2]: (warning) %lu in format string (no. 3) requires an unsigned long integer given in the argument list.\n" + "[test.cpp:2]: (warning) %f in format string (no. 4) requires a floating point number given in the argument list.\n" "[test.cpp:2]: (warning) %lf in format string (no. 5) requires a floating point number given in the argument list.\n" "[test.cpp:2]: (warning) %p in format string (no. 6) requires an address given in the argument list.\n", errout.str()); - check("long double f() { return 0; }\n" - "void foo() { printf(\"%d %ld %u %lu %f %p\", f(), f(), f(), f(), f(), f()); }"); - ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 1) requires a signed integer given in the argument list.\n" - "[test.cpp:2]: (warning) %ld in format string (no. 2) requires a signed long integer given in the argument list.\n" - "[test.cpp:2]: (warning) %u in format string (no. 3) requires an unsigned integer given in the argument list.\n" - "[test.cpp:2]: (warning) %lu in format string (no. 4) requires an unsigned long integer given in the argument list.\n" - "[test.cpp:2]: (warning) %f in format string (no. 5) requires a floating point number given in the argument list.\n" + check("struct Fred { int i; } f;\n" + "void foo() { printf(\"%d %u %lu %f %lf %p\", f.i, f.i, f.i, f.i, f.i, f.i); }"); + ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 2) requires an unsigned integer given in the argument list.\n" + "[test.cpp:2]: (warning) %lu in format string (no. 3) requires an unsigned long integer given in the argument list.\n" + "[test.cpp:2]: (warning) %f in format string (no. 4) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %lf in format string (no. 5) requires a floating point number given in the argument list.\n" "[test.cpp:2]: (warning) %p in format string (no. 6) requires an address given in the argument list.\n", errout.str()); - check("namespace bar { int f() { return 0; } }\n" - "void foo() { printf(\"%u %lu %f %lf %p\", bar::f(), bar::f(), bar::f(), bar::f(), bar::f()); }"); - ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 1) requires an unsigned integer given in the argument list.\n" - "[test.cpp:2]: (warning) %lu in format string (no. 2) requires an unsigned long integer given in the argument list.\n" - "[test.cpp:2]: (warning) %f in format string (no. 3) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %lf in format string (no. 4) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %p in format string (no. 5) requires an address given in the argument list.\n", errout.str()); - - check("struct Fred { int i; } f;\n" - "void foo() { printf(\"%u %lu %f %lf %p\", f.i, f.i, f.i, f.i, f.i); }"); - ASSERT_EQUALS("[test.cpp:2]: (warning) %u in format string (no. 1) requires an unsigned integer given in the argument list.\n" - "[test.cpp:2]: (warning) %lu in format string (no. 2) requires an unsigned long integer given in the argument list.\n" - "[test.cpp:2]: (warning) %f in format string (no. 3) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %lf in format string (no. 4) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %p in format string (no. 5) requires an address given in the argument list.\n", errout.str()); - check("struct Fred { unsigned int u; } f;\n" - "void foo() { printf(\"%d %ld %f %lf %p\", f.u, f.u, f.u, f.u, f.u); }"); - ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 1) requires a signed integer given in the argument list.\n" - "[test.cpp:2]: (warning) %ld in format string (no. 2) requires a signed long integer given in the argument list.\n" - "[test.cpp:2]: (warning) %f in format string (no. 3) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %lf in format string (no. 4) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %p in format string (no. 5) requires an address given in the argument list.\n", errout.str()); + "void foo() { printf(\"%u %d %ld %f %lf %p\", f.u, f.u, f.u, f.u, f.u, f.u); }"); + ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires a signed integer given in the argument list.\n" + "[test.cpp:2]: (warning) %ld in format string (no. 3) requires a signed long integer given in the argument list.\n" + "[test.cpp:2]: (warning) %f in format string (no. 4) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %lf in format string (no. 5) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %p in format string (no. 6) requires an address given in the argument list.\n", errout.str()); check("struct Fred { unsigned int ui() { return 0; } } f;\n" - "void foo() { printf(\"%d %ld %f %lf %p\", f.ui(), f.ui(), f.ui(), f.ui(), f.ui()); }"); - ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 1) requires a signed integer given in the argument list.\n" - "[test.cpp:2]: (warning) %ld in format string (no. 2) requires a signed long integer given in the argument list.\n" - "[test.cpp:2]: (warning) %f in format string (no. 3) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %lf in format string (no. 4) requires a floating point number given in the argument list.\n" - "[test.cpp:2]: (warning) %p in format string (no. 5) requires an address given in the argument list.\n", errout.str()); + "void foo() { printf(\"%u %d %ld %f %lf %p\", f.ui(), f.ui(), f.ui(), f.ui(), f.ui(), f.ui()); }"); + ASSERT_EQUALS("[test.cpp:2]: (warning) %d in format string (no. 2) requires a signed integer given in the argument list.\n" + "[test.cpp:2]: (warning) %ld in format string (no. 3) requires a signed long integer given in the argument list.\n" + "[test.cpp:2]: (warning) %f in format string (no. 4) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %lf in format string (no. 5) requires a floating point number given in the argument list.\n" + "[test.cpp:2]: (warning) %p in format string (no. 6) requires an address given in the argument list.\n", errout.str()); // #4975 check("void f(int len, int newline) {\n" @@ -955,6 +955,66 @@ private: " printf(\"%s\", newline + newline);\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + check("struct Fred { int i; } f;\n" + "struct Fred & bar() { };\n" + "void foo() { printf(\"%d %u %lu %f %lf %p\", bar().i, bar().i, bar().i, bar().i, bar().i, bar().i); }"); + ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires an unsigned integer given in the argument list.\n" + "[test.cpp:3]: (warning) %lu in format string (no. 3) requires an unsigned long integer given in the argument list.\n" + "[test.cpp:3]: (warning) %f in format string (no. 4) requires a floating point number given in the argument list.\n" + "[test.cpp:3]: (warning) %lf in format string (no. 5) requires a floating point number given in the argument list.\n" + "[test.cpp:3]: (warning) %p in format string (no. 6) requires an address given in the argument list.\n", errout.str()); + + check("struct Fred { int i; } f;\n" + "const struct Fred & bar() { };\n" + "void foo() { printf(\"%d %u %lu %f %lf %p\", bar().i, bar().i, bar().i, bar().i, bar().i, bar().i); }"); + ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires an unsigned integer given in the argument list.\n" + "[test.cpp:3]: (warning) %lu in format string (no. 3) requires an unsigned long integer given in the argument list.\n" + "[test.cpp:3]: (warning) %f in format string (no. 4) requires a floating point number given in the argument list.\n" + "[test.cpp:3]: (warning) %lf in format string (no. 5) requires a floating point number given in the argument list.\n" + "[test.cpp:3]: (warning) %p in format string (no. 6) requires an address given in the argument list.\n", errout.str()); + + check("struct Fred { int i; } f;\n" + "static const struct Fred & bar() { };\n" + "void foo() { printf(\"%d %u %lu %f %lf %p\", bar().i, bar().i, bar().i, bar().i, bar().i, bar().i); }"); + ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires an unsigned integer given in the argument list.\n" + "[test.cpp:3]: (warning) %lu in format string (no. 3) requires an unsigned long integer given in the argument list.\n" + "[test.cpp:3]: (warning) %f in format string (no. 4) requires a floating point number given in the argument list.\n" + "[test.cpp:3]: (warning) %lf in format string (no. 5) requires a floating point number given in the argument list.\n" + "[test.cpp:3]: (warning) %p in format string (no. 6) requires an address given in the argument list.\n", errout.str()); + + check("struct Fred { int i; } f[2];\n" + "struct Fred * bar() { return f; };\n" + "void foo() { printf(\"%d %u %lu %f %lf %p\", bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i); }"); + ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires an unsigned integer given in the argument list.\n" + "[test.cpp:3]: (warning) %lu in format string (no. 3) requires an unsigned long integer given in the argument list.\n" + "[test.cpp:3]: (warning) %f in format string (no. 4) requires a floating point number given in the argument list.\n" + "[test.cpp:3]: (warning) %lf in format string (no. 5) requires a floating point number given in the argument list.\n" + "[test.cpp:3]: (warning) %p in format string (no. 6) requires an address given in the argument list.\n", errout.str()); + + check("struct Fred { int i; } f[2];\n" + "const struct Fred * bar() { return f; };\n" + "void foo() { printf(\"%d %u %lu %f %lf %p\", bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i); }"); + ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires an unsigned integer given in the argument list.\n" + "[test.cpp:3]: (warning) %lu in format string (no. 3) requires an unsigned long integer given in the argument list.\n" + "[test.cpp:3]: (warning) %f in format string (no. 4) requires a floating point number given in the argument list.\n" + "[test.cpp:3]: (warning) %lf in format string (no. 5) requires a floating point number given in the argument list.\n" + "[test.cpp:3]: (warning) %p in format string (no. 6) requires an address given in the argument list.\n", errout.str()); + + check("struct Fred { int i; } f[2];\n" + "static const struct Fred * bar() { return f; };\n" + "void foo() { printf(\"%d %u %lu %f %lf %p\", bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i, bar()[0].i); }"); + ASSERT_EQUALS("[test.cpp:3]: (warning) %u in format string (no. 2) requires an unsigned integer given in the argument list.\n" + "[test.cpp:3]: (warning) %lu in format string (no. 3) requires an unsigned long integer given in the argument list.\n" + "[test.cpp:3]: (warning) %f in format string (no. 4) requires a floating point number given in the argument list.\n" + "[test.cpp:3]: (warning) %lf in format string (no. 5) requires a floating point number given in the argument list.\n" + "[test.cpp:3]: (warning) %p in format string (no. 6) requires an address given in the argument list.\n", errout.str()); + + check("struct Fred { int32_t i; } f;\n" + "struct Fred & bar() { };\n" + "void foo() { printf(\"%d %ld %u %lu %f %lf\", bar().i, bar().i, bar().i, bar().i, bar().i, bar().i); }"); + ASSERT_EQUALS("", errout.str()); + } void testPosixPrintfScanfParameterPosition() { // #4900 - No support for parameters in format strings