From 509061afff4c05c1715432d23590726a4ef1d7e9 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Wed, 27 Feb 2013 06:59:04 +0100 Subject: [PATCH] Fixed #4620 (False positive: Uninitialized variable in constructor (1.58)) --- lib/checkclass.cpp | 22 +++++++++++----------- lib/symboldatabase.cpp | 16 +++++++++++----- lib/symboldatabase.h | 3 +++ test/testconstructors.cpp | 22 ++++++++++++++++++++++ 4 files changed, 47 insertions(+), 16 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index b854e3e4e..b5ab57965 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -364,10 +364,8 @@ void CheckClass::initializeVarList(const Function &func, std::liststr() != func.name()) { - initVar(ftok->str(), scope, usage); - } else { // c++11 delegate constructor + if (level == 0 && Token::Match(ftok, "%type% (")) { + if (ftok->str() == func.name()) { // c++11 delegate constructor const Function *member = scope->findFunction(ftok); // member function found if (member) { @@ -392,7 +390,10 @@ void CheckClass::initializeVarList(const Function &func, std::liststr(), scope, usage); } else if (level == 0 && Token::Match(ftok, "%var% {") && ftok->str() != "const" && Token::Match(ftok->next()->link()->next(), ",|{|%type%")) { initVar(ftok->str(), scope, usage); ftok = ftok->linkAt(1); @@ -496,9 +497,8 @@ void CheckClass::initializeVarList(const Function &func, std::listprevious()->str() != "::") { - const Function *member = scope->findFunction(ftok); - // member function found - if (member) { + if (ftok->function() && ftok->function()->nestedIn == scope) { + const Function *member = ftok->function(); // recursive call // assume that all variables are initialized if (std::find(callstack.begin(), callstack.end(), member) != callstack.end()) { @@ -538,10 +538,10 @@ void CheckClass::initializeVarList(const Function &func, std::listfindFunction(ftok); + if (ftok->function() && ftok->function()->nestedIn == scope && + ftok->function()->type != Function::eConstructor) { + const Function *member = ftok->function(); - // member function found - if (member && member->type != Function::eConstructor) { // recursive call // assume that all variables are initialized if (std::find(callstack.begin(), callstack.end(), member) != callstack.end()) { @@ -801,7 +801,7 @@ void CheckClass::unusedPrivateFunctionError(const Token *tok, const std::string // ClassCheck: Check that memset is not used on classes //--------------------------------------------------------------------------- -const Scope* findFunctionOf(const Scope* scope) +static const Scope* findFunctionOf(const Scope* scope) { while (scope) { if (scope->type == Scope::eFunction) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 0a3784a3e..eaece1adb 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1885,7 +1885,6 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s // skip default values if (tok->str() == "=") { - initArgCount++; while (tok->str() != "," && tok->str() != ")") { if (tok->link() && Token::Match(tok, "[{[(<]")) tok = tok->link(); @@ -1898,6 +1897,12 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s if (tok->str() == ")") break; } + + // count deafult arguments + for (const Token* tok = argDef->next(); tok && tok != argDef->link(); tok = tok->next()) { + if (tok->str() == "=") + initArgCount++; + } } } @@ -2378,7 +2383,7 @@ const Scope *SymbolDatabase::findVariableType(const Scope *start, const Token *t //--------------------------------------------------------------------------- /** @todo This function only counts the number of arguments in the function call. - It does not take into account functions with default arguments. + It does not take into account function constantness. It does not take into account argument types. This can be difficult because of promotion and conversion operators and casts and because the argument can also be a function call. */ const Function* Scope::findFunction(const Token *tok) const @@ -2388,7 +2393,7 @@ const Function* Scope::findFunction(const Token *tok) const const Function *func = &*i; if (tok->strAt(1) == "(" && tok->tokAt(2)) { // check if function has no arguments - if (tok->strAt(2) == ")" && (func->argCount() == 0 || func->argCount() == func->initializedArgCount())) + if (tok->strAt(2) == ")" && (func->argCount() == 0 || func->minArgCount() == 0)) return func; // check the arguments @@ -2396,12 +2401,13 @@ const Function* Scope::findFunction(const Token *tok) const const Token *arg = tok->tokAt(2); while (arg && arg->str() != ")") { /** @todo check argument type for match */ - /** @todo check for default arguments */ args++; arg = arg->nextArgument(); } - if (args == func->argCount()) + // check for argument count match or default arguments + if (args == func->argCount() || + (args < func->argCount() && args >= func->minArgCount())) return func; } } diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 00463c424..9d2a55ed1 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -403,6 +403,9 @@ public: std::size_t argCount() const { return argumentList.size(); } + std::size_t minArgCount() const { + return argumentList.size() - initArgCount; + } const Variable* getArgumentVar(unsigned int num) const; unsigned int initializedArgCount() const { return initArgCount; diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index 06ae613d0..62399ddc2 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -64,6 +64,7 @@ private: TEST_CASE(simple9); // ticket #4574 TEST_CASE(simple10); // ticket #4388 TEST_CASE(simple11); // ticket #4536 + TEST_CASE(simple12); // ticket #4620 TEST_CASE(initvar_with_this); // BUG 2190300 TEST_CASE(initvar_if); // BUG 2190290 @@ -353,6 +354,27 @@ private: ASSERT_EQUALS("", errout.str()); } + void simple12() { // ticket #4620 + check("class Fred {\n" + " int x;\n" + "public:\n" + " Fred() { Init(); }\n" + " void Init(int i = 0);\n" + "};\n" + "void Fred::Init(int i) { x = i; }\n"); + ASSERT_EQUALS("", errout.str()); + + check("class Fred {\n" + " int x;\n" + " int y;\n" + "public:\n" + " Fred() { Init(0); }\n" + " void Init(int i, int j = 0);\n" + "};\n" + "void Fred::Init(int i, int j) { x = i; y = j; }\n"); + ASSERT_EQUALS("", errout.str()); + } + void initvar_with_this() { check("struct Fred\n" "{\n"