diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 18cbf3b79..937c2874f 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -686,6 +686,21 @@ void CheckClass::assignAllVar(std::vector &usageList) i.assign = true; } +void CheckClass::assignAllVarsVisibleFromScope(std::vector& usageList, const Scope* scope) +{ + for (Usage& usage : usageList) { + if (usage.var->scope() == scope) + usage.assign = true; + } + + // Iterate through each base class... + for (const Type::BaseInfo& i : scope->definedType->derivedFrom) { + const Type *derivedFrom = i.type; + + assignAllVarsVisibleFromScope(usageList, derivedFrom->classScope); + } +} + void CheckClass::clearAllVar(std::vector &usageList) { for (Usage & i : usageList) { @@ -694,7 +709,7 @@ void CheckClass::clearAllVar(std::vector &usageList) } } -bool CheckClass::isBaseClassFunc(const Token *tok, const Scope *scope) +bool CheckClass::isBaseClassMutableMemberFunc(const Token *tok, const Scope *scope) { // Iterate through each base class... for (const Type::BaseInfo & i : scope->definedType->derivedFrom) { @@ -705,11 +720,11 @@ bool CheckClass::isBaseClassFunc(const Token *tok, const Scope *scope) const std::list& functionList = derivedFrom->classScope->functionList; if (std::any_of(functionList.begin(), functionList.end(), [&](const Function& func) { - return func.tokenDef->str() == tok->str(); + return func.tokenDef->str() == tok->str() && !func.isStatic() && !func.isConst(); })) return true; - if (isBaseClassFunc(tok, derivedFrom->classScope)) + if (isBaseClassMutableMemberFunc(tok, derivedFrom->classScope)) return true; } @@ -894,6 +909,12 @@ void CheckClass::initializeVarList(const Function &func, std::liststr() == ftok->str() && isBaseClassMutableMemberFunc(ftok, scope)) { + if (member->nestedIn) + assignAllVarsVisibleFromScope(usage, member->nestedIn->definedType->classScope); + } + // there is a called member function, but it has no implementation, so we assume it initializes everything else { assignAllVar(usage); @@ -949,8 +970,8 @@ void CheckClass::initializeVarList(const Function &func, std::listisConst() && !member->isStatic()) { assignAllVar(usage); } } @@ -958,7 +979,7 @@ void CheckClass::initializeVarList(const Function &func, std::list &usageList); + /** + * @brief set all variable in list assigned, if visible from given scope + * @param usageList reference to usage vector + * @param scope scope from which usages must be visible + */ + static void assignAllVarsVisibleFromScope(std::vector &usageList, const Scope *scope); + /** * @brief set all variables in list not assigned and not initialized * @param usageList reference to usage vector diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index 7b0af6b78..b6ec94996 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -116,6 +116,7 @@ private: TEST_CASE(initvar_operator_eq5); // ticket #4119 TEST_CASE(initvar_operator_eq6); TEST_CASE(initvar_operator_eq7); + TEST_CASE(initvar_operator_eq8); TEST_CASE(initvar_same_classname); // BUG 2208157 TEST_CASE(initvar_chained_assign); // BUG 2270433 TEST_CASE(initvar_2constructors); // BUG 2270353 @@ -981,6 +982,30 @@ private: ASSERT_EQUALS("", errout.str()); } + void initvar_operator_eq8() { + check("struct B {\n" + " int b;\n" + "};\n" + "struct D1 : B {\n" + " D1& operator=(const D1& src);\n" + " int d1;\n" + "};\n" + "struct D2 : D1 {\n" + " D2& operator=(const D2& src);\n" + " int d2;\n" + "};\n" + "struct D3 : D2 {\n" + " D3& operator=(const D3& src) {\n" + " D1::operator=(src);\n" + " d3_1 = src.d3_1;\n" + " }\n" + " int d3_1;\n" + " int d3_2;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:13]: (warning) Member variable 'D3::d3_2' is not assigned a value in 'D3::operator='.\n" + "[test.cpp:13]: (warning) Member variable 'D3::d2' is not assigned a value in 'D3::operator='.\n", errout.str()); + } + void initvar_same_classname() { // Bug 2208157 - False positive: Uninitialized variable, same class name @@ -3324,6 +3349,38 @@ private: "};"); ASSERT_EQUALS("[test.cpp:5]: (warning) Member variable 'Fred::i' is not initialized in the constructor.\n", errout.str()); + // Unknown member functions and unknown static functions + check("class ABC {\n" + " static void static_base_func();\n" + " void const_base_func() const;\n" + "};\n" + "class Fred : private ABC {\n" + "public:\n" + " Fred() {\n" + " const_func();\n" + " static_func();\n" + " const_base_func();\n" + " ABC::static_base_func();\n" + " }\n" + " void const_func() const;\n" + " static void static_f();\n" + "private:\n" + " int i;\n" + "};"); + + // Unknown overloaded member functions + check("class Fred : private ABC {\n" + "public:\n" + " Fred() {\n" + " func();\n" + " }\n" + " void func() const;\n" + " void func();\n" + "private:\n" + " int i;\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } void uninitVarEnum1() {