diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 1c9122458..a581df4a8 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -340,11 +340,14 @@ void CheckClass::copyconstructors() } if (!funcCopyCtor || funcCopyCtor->isDefault()) { bool unknown = false; - if (!isNonCopyable(scope, &unknown)) + if (!isNonCopyable(scope, &unknown) && !unknown) noCopyConstructorError(scope, funcCopyCtor, allocatedVars.begin()->second, unknown); } - if (!funcOperatorEq || funcOperatorEq->isDefault()) - noOperatorEqError(scope, funcOperatorEq, allocatedVars.begin()->second); + if (!funcOperatorEq || funcOperatorEq->isDefault()) { + bool unknown = false; + if (!isNonCopyable(scope, &unknown) && !unknown) + noOperatorEqError(scope, funcOperatorEq, allocatedVars.begin()->second, unknown); + } if (!funcDestructor || funcDestructor->isDefault()) { const Token * mustDealloc = nullptr; for (std::map::const_iterator it = allocatedVars.begin(); it != allocatedVars.end(); ++it) { @@ -452,9 +455,9 @@ void CheckClass::noCopyConstructorError(const Scope *scope, bool isdefault, cons reportError(alloc, Severity::style, "noCopyConstructor", noMemberErrorMessage(scope, "copy constructor", isdefault), CWE398, inconclusive); } -void CheckClass::noOperatorEqError(const Scope *scope, bool isdefault, const Token *alloc) +void CheckClass::noOperatorEqError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive) { - reportError(alloc, Severity::style, "noOperatorEq", noMemberErrorMessage(scope, "operator=", isdefault), CWE398, false); + reportError(alloc, Severity::style, "noOperatorEq", noMemberErrorMessage(scope, "operator=", isdefault), CWE398, inconclusive); } void CheckClass::noDestructorError(const Scope *scope, bool isdefault, const Token *alloc) diff --git a/lib/checkclass.h b/lib/checkclass.h index 079bf3896..317e3afd3 100644 --- a/lib/checkclass.h +++ b/lib/checkclass.h @@ -169,7 +169,7 @@ private: //void copyConstructorMallocError(const Token *cctor, const Token *alloc, const std::string& var_name); void copyConstructorShallowCopyError(const Token *tok, const std::string& varname); void noCopyConstructorError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive); - void noOperatorEqError(const Scope *scope, bool isdefault, const Token *alloc); + void noOperatorEqError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive); void noDestructorError(const Scope *scope, bool isdefault, const Token *alloc); void uninitVarError(const Token *tok, bool isprivate, const std::string &classname, const std::string &varname, bool inconclusive); void operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive); @@ -205,7 +205,7 @@ private: //c.copyConstructorMallocError(nullptr, 0, "var"); c.copyConstructorShallowCopyError(nullptr, "var"); c.noCopyConstructorError(nullptr, false, nullptr, false); - c.noOperatorEqError(nullptr, false, nullptr); + c.noOperatorEqError(nullptr, false, nullptr, false); c.noDestructorError(nullptr, false, nullptr); c.uninitVarError(nullptr, false, "classname", "varname", false); c.operatorEqVarError(nullptr, "classname", emptyString, false); diff --git a/test/testclass.cpp b/test/testclass.cpp index 84e3ca5a3..20ece9261 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -736,7 +736,7 @@ private: " ~F();\n" " F& operator=(const F&f);\n" "};"); - ASSERT_EQUALS("[test.cpp:5]: (style, inconclusive) Class 'F' does not have a copy constructor which is recommended since it has dynamic memory/resource allocation(s).\n", errout.str()); + ASSERT_EQUALS("", errout.str()); checkCopyConstructor("class E { E(E&); };\n" // non-copyable "class F : E\n" @@ -855,6 +855,15 @@ private: " ~F();\n" "};"); ASSERT_EQUALS("", errout.str()); + + // base class deletes operator= + checkCopyConstructor("struct F : NonCopyable {\n" + " char* c;\n" + " F() { c = malloc(100); }\n" + " F(const F &f);\n" + " ~F();\n" + "};"); + ASSERT_EQUALS("", errout.str()); } void noDestructor() {