diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 8fc748b0b..c1f5e9fd7 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -65,6 +65,11 @@ static const char * getFunctionTypeName(Function::Type type) return ""; } +static bool isVariableCopyNeeded(const Variable &var) +{ + return var.isPointer() || (var.type() && var.type()->needInitialization == Type::True) || (var.valueType()->type >= ValueType::Type::CHAR); +} + //--------------------------------------------------------------------------- CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) @@ -156,6 +161,9 @@ void CheckClass::constructors() if (usage[count].assign || usage[count].init || var.isStatic()) continue; + if (var.valueType()->pointer == 0 && var.type() && var.type()->needInitialization == Type::False) + continue; + if (var.isConst() && func.isOperator()) // We can't set const members in assignment operator continue; @@ -185,16 +193,11 @@ void CheckClass::constructors() bool inconclusive = false; // Don't warn about unknown types in copy constructors since we // don't know if they can be copied or not.. - if (!var.isPointer() && - !(var.type() && var.type()->needInitialization != Type::True) && - (func.type == Function::eCopyConstructor || func.type == Function::eOperatorEqual)) { - if (var.valueType()->type <= ValueType::Type::RECORD) { - if (printInconclusive) - inconclusive = true; - else - continue; - } - } + if ((func.type == Function::eCopyConstructor || func.type == Function::eOperatorEqual) && !isVariableCopyNeeded(var)) + inconclusive = true; + + if (!printInconclusive && inconclusive) + continue; // It's non-static and it's not initialized => error if (func.type == Function::eOperatorEqual) { diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index bfd3610b3..42bb82323 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -88,6 +88,7 @@ private: TEST_CASE(initvar_operator_eq3); TEST_CASE(initvar_operator_eq4); // ticket #2204 TEST_CASE(initvar_operator_eq5); // ticket #4119 + TEST_CASE(initvar_operator_eq6); TEST_CASE(initvar_same_classname); // BUG 2208157 TEST_CASE(initvar_chained_assign); // BUG 2270433 TEST_CASE(initvar_2constructors); // BUG 2270353 @@ -764,6 +765,32 @@ private: ASSERT_EQUALS("", errout.str()); } + void initvar_operator_eq6() { // std::vector + check("struct Fred {\n" + " uint8_t data;\n" + " Fred & operator=(const Fred &rhs) {\n" + " return *this;\n" + " }\n" + "};",true); + ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) Member variable 'Fred::data' is not assigned a value in 'Fred::operator='.\n", errout.str()); + + check("struct Fred {\n" + " std::vector ints;\n" + " Fred & operator=(const Fred &rhs) {\n" + " return *this;\n" + " }\n" + "};",true); + ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) Member variable 'Fred::ints' is not assigned a value in 'Fred::operator='.\n", errout.str()); + + check("struct Fred {\n" + " Data data;\n" + " Fred & operator=(const Fred &rhs) {\n" + " return *this;\n" + " }\n" + "};",true); + ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) Member variable 'Fred::data' is not assigned a value in 'Fred::operator='.\n", errout.str()); + } + void initvar_same_classname() { // Bug 2208157 - False positive: Uninitialized variable, same class name @@ -1327,14 +1354,13 @@ private: " A(A &&){}\n" " const A& operator=(const A&){return *this;}\n" "};"); - ASSERT_EQUALS("[test.cpp:11]: (warning) Member variable 'A::m_SemVar' is not initialized in the constructor.\n" - "[test.cpp:12]: (warning) Member variable 'A::m_SemVar' is not initialized in the constructor.\n" - "[test.cpp:13]: (warning) Member variable 'A::m_SemVar' is not assigned a value in 'A::operator='.\n", errout.str()); + ASSERT_EQUALS("", errout.str()); check("class B\n" "{\n" "public:\n" " B (B && Var);\n" + " int data;\n" "};\n" "class A\n" "{\n" @@ -1345,13 +1371,14 @@ private: " A(A &&){}\n" " const A& operator=(const A&){return *this;}\n" "};"); - ASSERT_EQUALS("[test.cpp:12]: (warning) Member variable 'A::m_SemVar' is not initialized in the constructor.\n", errout.str()); + ASSERT_EQUALS("[test.cpp:13]: (warning) Member variable 'A::m_SemVar' is not initialized in the constructor.\n", errout.str()); check("class B\n" "{\n" "public:\n" " B ();\n" " B & operator= (const B & Var);\n" + " int data;\n" "};\n" "class A\n" "{\n" @@ -1362,9 +1389,7 @@ private: " A(A &&){}\n" " const A& operator=(const A&){return *this;}\n" "};"); - ASSERT_EQUALS("[test.cpp:12]: (warning) Member variable 'A::m_SemVar' is not initialized in the constructor.\n" - "[test.cpp:13]: (warning) Member variable 'A::m_SemVar' is not initialized in the constructor.\n" - "[test.cpp:14]: (warning) Member variable 'A::m_SemVar' is not assigned a value in 'A::operator='.\n", errout.str()); + ASSERT_EQUALS("", errout.str()); check("class A\n" "{\n" @@ -1382,6 +1407,7 @@ private: "{\n" " B (B & Var);\n" " B & operator= (const B & Var);\n" + " int data;\n" "};\n" "class A\n" "{\n" @@ -1390,7 +1416,7 @@ private: " A(){}\n" " A(const A&){}\n" " const A& operator=(const A&){return *this;}\n" - "};"); + "};", true); ASSERT_EQUALS("", errout.str()); check("class B\n" @@ -1398,6 +1424,7 @@ private: "public:\n" " B (B & Var);\n" " B & operator= (const B & Var);\n" + " int data;\n" "};\n" "class A\n" "{\n" @@ -1406,9 +1433,10 @@ private: " A(){}\n" " A(const A&){}\n" " const A& operator=(const A&){return *this;}\n" - "};"); + "};", true); ASSERT_EQUALS("[test.cpp:12]: (warning) Member variable 'A::m_SemVar' is not initialized in the constructor.\n" - "[test.cpp:13]: (warning) Member variable 'A::m_SemVar' is not assigned a value in 'A::operator='.\n", errout.str()); + "[test.cpp:13]: (warning) Member variable 'A::m_SemVar' is not initialized in the constructor.\n" + "[test.cpp:14]: (warning) Member variable 'A::m_SemVar' is not assigned a value in 'A::operator='.\n", errout.str()); } void initvar_nocopy3() { // #3611 - unknown type is non-copyable