From d1eb04c5393bd72dee2a56c36dbaca3cdf3ff490 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Wed, 12 Mar 2014 05:48:13 +0100 Subject: [PATCH] Fixed #4302 (Member variable not initialized in public delegate constructor) --- lib/checkclass.cpp | 29 ++++++++++++++++++++++++++++- lib/symboldatabase.cpp | 5 +++-- test/testconstructors.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 18d9160ed..d7b9b0f10 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -469,7 +469,34 @@ void CheckClass::initializeVarList(const Function &func, std::liststr() != "const" && Token::Match(ftok->next()->link()->next(), "%type%|,|{")) { - initVar(ftok->str(), scope, usage); + if (ftok->str() != func.name()) { + initVar(ftok->str(), scope, usage); + } else { // c++11 delegate constructor + const Function *member = scope->findFunction(ftok); + // member function found + if (member) { + // recursive call + // assume that all variables are initialized + if (std::find(callstack.begin(), callstack.end(), member) != callstack.end()) { + /** @todo false negative: just bail */ + assignAllVar(usage); + return; + } + + // member function has implementation + if (member->hasBody) { + // initialize variable use list using member function + callstack.push_back(member); + initializeVarList(*member, callstack, scope, usage); + callstack.pop_back(); + } + + // there is a called member function, but it has no implementation, so we assume it initializes everything + else { + assignAllVar(usage); + } + } + } ftok = ftok->linkAt(1); } else if (level != 0 && Token::Match(ftok, "%var% =")) // assignment in the initializer: var(value = x) assignVar(ftok->str(), scope, usage); diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index bb08ac289..b0b37b07d 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -2500,11 +2500,12 @@ const Function* Scope::findFunction(const Token *tok) const for (std::list::const_iterator i = functionList.begin(); i != functionList.end(); ++i) { if (i->tokenDef->str() == tok->str()) { const Function *func = &*i; - if (tok->strAt(1) == "(" && tok->tokAt(2)) { + if ((tok->strAt(1) == "(" || (func->name() == tok->str() && tok->strAt(1) == "{" && func->type == Function::eConstructor)) && tok->tokAt(2)) { + std::string end(tok->strAt(1) == "{" ? "}" : ")"); // check the arguments unsigned int args = 0; const Token *arg = tok->tokAt(2); - while (arg && arg->str() != ")") { + while (arg && arg->str() != end) { /** @todo check argument type for match */ // mismatch parameter: passing parameter by address to function, argument is reference diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index b3f0fec13..130b25256 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -832,6 +832,40 @@ private: " A() { number = 42; }\n" "};"); ASSERT_EQUALS("", errout.str()); + + check("class A {\n" + " int number;\n" + "public:\n" + " A(int n) { }\n" + " A() : A{42} {}\n" + "};"); + ASSERT_EQUALS("[test.cpp:4]: (warning) Member variable 'A::number' is not initialized in the constructor.\n" + "[test.cpp:5]: (warning) Member variable 'A::number' is not initialized in the constructor.\n", errout.str()); + + check("class A {\n" + " int number;\n" + "public:\n" + " A(int n) { number = n; }\n" + " A() : A{42} {}\n" + "};"); + ASSERT_EQUALS("", errout.str()); + + check("class A {\n" + " int number;\n" + "public:\n" + " A(int n) : A{} { }\n" + " A() {}\n" + "};", true); + ASSERT_EQUALS("[test.cpp:4]: (warning) Member variable 'A::number' is not initialized in the constructor.\n" + "[test.cpp:5]: (warning, inconclusive) Member variable 'A::number' is not initialized in the constructor.\n", errout.str()); + + check("class A {\n" + " int number;\n" + "public:\n" + " A(int n) : A{} { }\n" + " A() { number = 42; }\n" + "};"); + ASSERT_EQUALS("", errout.str()); }