Class: Show inconclusive warnings about unknown types that are not initialized in copy constructors. Ticket: #3611

This commit is contained in:
Daniel Marjamäki 2012-09-20 19:16:26 +02:00
parent 07db469c06
commit de8e592d00
3 changed files with 55 additions and 18 deletions

View File

@ -107,6 +107,8 @@ void CheckClass::constructors()
std::list<Variable>::const_iterator var; std::list<Variable>::const_iterator var;
unsigned int count = 0; unsigned int count = 0;
for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var, ++count) { for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var, ++count) {
bool inconclusive = false;
if (usage[count].assign || usage[count].init || var->isStatic()) if (usage[count].assign || usage[count].init || var->isStatic())
continue; continue;
@ -131,12 +133,18 @@ void CheckClass::constructors()
// Don't warn about unknown types in copy constructors since we // Don't warn about unknown types in copy constructors since we
// don't know if they can be copied or not.. // don't know if they can be copied or not..
if (!var->isPointer() && !var->isClass() && (func->type == Function::eCopyConstructor || func->type == Function::eOperatorEqual)) { if (!var->isPointer() &&
!(var->type() && var->type()->needInitialization != Scope::True) &&
(func->type == Function::eCopyConstructor || func->type == Function::eOperatorEqual)) {
bool stdtype = false; bool stdtype = false;
for (const Token *type = var->typeStartToken(); type && type->isName(); type = type->next()) for (const Token *type = var->typeStartToken(); type && type->isName(); type = type->next())
stdtype |= type->isStandardType(); stdtype |= type->isStandardType();
if (!stdtype) if (!stdtype) {
continue; if (_settings->inconclusive)
inconclusive = true;
else
continue;
}
} }
// It's non-static and it's not initialized => error // It's non-static and it's not initialized => error
@ -152,11 +160,11 @@ void CheckClass::constructors()
} }
if (classNameUsed) if (classNameUsed)
operatorEqVarError(func->token, scope->className, var->name()); operatorEqVarError(func->token, scope->className, var->name(), inconclusive);
} else if (func->access != Private) { } else if (func->access != Private) {
const Scope *varType = var->type(); const Scope *varType = var->type();
if (!varType || varType->type != Scope::eUnion) if (!varType || varType->type != Scope::eUnion)
uninitVarError(func->token, scope->className, var->name()); uninitVarError(func->token, scope->className, var->name(), inconclusive);
} }
} }
} }
@ -593,14 +601,14 @@ void CheckClass::noConstructorError(const Token *tok, const std::string &classna
"instanciated. That may cause bugs or undefined behavior."); "instanciated. That may cause bugs or undefined behavior.");
} }
void CheckClass::uninitVarError(const Token *tok, const std::string &classname, const std::string &varname) void CheckClass::uninitVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive)
{ {
reportError(tok, Severity::warning, "uninitMemberVar", "Member variable '" + classname + "::" + varname + "' is not initialized in the constructor."); reportError(tok, Severity::warning, "uninitMemberVar", "Member variable '" + classname + "::" + varname + "' is not initialized in the constructor.", inconclusive);
} }
void CheckClass::operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname) void CheckClass::operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive)
{ {
reportError(tok, Severity::warning, "operatorEqVarError", "Member variable '" + classname + "::" + varname + "' is not assigned a value in '" + classname + "::operator='."); reportError(tok, Severity::warning, "operatorEqVarError", "Member variable '" + classname + "::" + varname + "' is not assigned a value in '" + classname + "::operator='.", inconclusive);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -126,8 +126,8 @@ private:
//void copyConstructorMallocError(const Token *cctor, const Token *alloc, const std::string& var_name); //void copyConstructorMallocError(const Token *cctor, const Token *alloc, const std::string& var_name);
void copyConstructorShallowCopyError(const Token *tok, const std::string& varname); void copyConstructorShallowCopyError(const Token *tok, const std::string& varname);
void noCopyConstructorError(const Token *tok, const std::string &classname, bool isStruct); void noCopyConstructorError(const Token *tok, const std::string &classname, bool isStruct);
void uninitVarError(const Token *tok, const std::string &classname, const std::string &varname); void uninitVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive);
void operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname); void operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive);
void unusedPrivateFunctionError(const Token *tok, const std::string &classname, const std::string &funcname); void unusedPrivateFunctionError(const Token *tok, const std::string &classname, const std::string &funcname);
void memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type); void memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type);
void operatorEqReturnError(const Token *tok, const std::string &className); void operatorEqReturnError(const Token *tok, const std::string &className);
@ -146,8 +146,8 @@ private:
//c.copyConstructorMallocError(0, 0, "var"); //c.copyConstructorMallocError(0, 0, "var");
c.copyConstructorShallowCopyError(0, "var"); c.copyConstructorShallowCopyError(0, "var");
c.noCopyConstructorError(0, "class", false); c.noCopyConstructorError(0, "class", false);
c.uninitVarError(0, "classname", "varname"); c.uninitVarError(0, "classname", "varname", false);
c.operatorEqVarError(0, "classname", ""); c.operatorEqVarError(0, "classname", "", false);
c.unusedPrivateFunctionError(0, "classname", "funcname"); c.unusedPrivateFunctionError(0, "classname", "funcname");
c.memsetError(0, "memfunc", "classname", "class"); c.memsetError(0, "memfunc", "classname", "class");
c.operatorEqReturnError(0, "class"); c.operatorEqReturnError(0, "class");

View File

@ -77,6 +77,7 @@ private:
TEST_CASE(initvar_nested_constructor); // ticket #1375 TEST_CASE(initvar_nested_constructor); // ticket #1375
TEST_CASE(initvar_nocopy1); // ticket #2474 TEST_CASE(initvar_nocopy1); // ticket #2474
TEST_CASE(initvar_nocopy2); // ticket #2484 TEST_CASE(initvar_nocopy2); // ticket #2484
TEST_CASE(initvar_nocopy3); // ticket #3611
TEST_CASE(initvar_destructor); // No variables need to be initialized in a destructor TEST_CASE(initvar_destructor); // No variables need to be initialized in a destructor
@ -677,7 +678,7 @@ private:
" Fred() { };\n" " Fred() { };\n"
" Fred(const Fred &) { };\n" " Fred(const Fred &) { };\n"
"};"); "};");
ASSERT_EQUALS("[test.cpp:7]: (warning) Member variable 'Fred::var' is not initialized in the constructor.\n", errout.str()); ASSERT_EQUALS("", errout.str());
check("class Fred\n" check("class Fred\n"
"{\n" "{\n"
@ -689,7 +690,29 @@ private:
"};\n" "};\n"
"Fred::Fred() { };\n" "Fred::Fred() { };\n"
"Fred::Fred(const Fred &) { };\n"); "Fred::Fred(const Fred &) { };\n");
ASSERT_EQUALS("[test.cpp:10]: (warning) Member variable 'Fred::var' is not initialized in the constructor.\n", errout.str()); ASSERT_EQUALS("", errout.str());
check("class Fred\n"
"{\n"
"private:\n"
" std::string var;\n"
"public:\n"
" Fred() { };\n"
" Fred(const Fred &) { };\n"
"};", true);
ASSERT_EQUALS("[test.cpp:7]: (warning, inconclusive) Member variable 'Fred::var' is not initialized in the constructor.\n", errout.str());
check("class Fred\n"
"{\n"
"private:\n"
" std::string var;\n"
"public:\n"
" Fred();\n"
" Fred(const Fred &);\n"
"};\n"
"Fred::Fred() { };\n"
"Fred::Fred(const Fred &) { };\n", true);
ASSERT_EQUALS("[test.cpp:10]: (warning, inconclusive) Member variable 'Fred::var' is not initialized in the constructor.\n", errout.str());
} }
void initvar_nested_constructor() { // ticket #1375 void initvar_nested_constructor() { // ticket #1375
@ -823,8 +846,7 @@ private:
" A(const A&){}\n" " A(const A&){}\n"
" const A& operator=(const A&){return *this;}\n" " const A& operator=(const A&){return *this;}\n"
"};\n"); "};\n");
ASSERT_EQUALS("[test.cpp:6]: (warning) Member variable 'A::m_SemVar' is not initialized in the constructor.\n" ASSERT_EQUALS("", errout.str());
"[test.cpp:7]: (warning) Member variable 'A::m_SemVar' is not assigned a value in 'A::operator='.\n", errout.str());
} }
void initvar_nocopy2() { // ticket #2484 void initvar_nocopy2() { // ticket #2484
@ -868,6 +890,13 @@ private:
" A(const A& rhs) {}\n" " A(const A& rhs) {}\n"
"};"); "};");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
check("struct A {\n"
" B b;\n"
" A() {}\n"
" A(const A& rhs) {}\n"
"};", true);
ASSERT_EQUALS("[test.cpp:4]: (warning, inconclusive) Member variable 'A::b' is not initialized in the constructor.\n", errout.str());
} }
void initvar_destructor() { void initvar_destructor() {
@ -897,7 +926,7 @@ private:
"\n" "\n"
"void Fred::operator=(const Fred &f)\n" "void Fred::operator=(const Fred &f)\n"
"{ }", true); "{ }", true);
ASSERT_EQUALS("[test.cpp:13]: (warning) Member variable 'Fred::ints' is not assigned a value in 'Fred::operator='.\n", errout.str()); ASSERT_EQUALS("[test.cpp:13]: (warning, inconclusive) Member variable 'Fred::ints' is not assigned a value in 'Fred::operator='.\n", errout.str());
} }
void uninitVar1() { void uninitVar1() {