CheckClass: Write separate errorid for missing member copy instead of uninitMember

This commit is contained in:
Daniel Marjamäki 2022-02-02 20:44:10 +01:00
parent 511520d623
commit 4d9a1427b2
2 changed files with 32 additions and 19 deletions

View File

@ -239,14 +239,17 @@ void CheckClass::constructors()
} }
} }
bool inconclusive = false; // Is there missing member copy in copy/move constructor or assignment operator?
bool missingCopy = false;
// 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 ((func.type == Function::eCopyConstructor || func.type == Function::eMoveConstructor || func.type == Function::eOperatorEqual) && !isVariableCopyNeeded(var)) if ((func.type == Function::eCopyConstructor || func.type == Function::eMoveConstructor || func.type == Function::eOperatorEqual) && !isVariableCopyNeeded(var)) {
inconclusive = true; if (!printInconclusive)
continue;
if (!printInconclusive && inconclusive) missingCopy = true;
continue; }
// It's non-static and it's not initialized => error // It's non-static and it's not initialized => error
if (func.type == Function::eOperatorEqual) { if (func.type == Function::eOperatorEqual) {
@ -261,7 +264,7 @@ void CheckClass::constructors()
} }
if (classNameUsed) if (classNameUsed)
operatorEqVarError(func.token, scope->className, var.name(), inconclusive); operatorEqVarError(func.token, scope->className, var.name(), missingCopy);
} else if (func.access != AccessControl::Private || mSettings->standards.cpp >= Standards::CPP11) { } else if (func.access != AccessControl::Private || mSettings->standards.cpp >= Standards::CPP11) {
// If constructor is not in scope then we maybe using a constructor from a different template specialization // If constructor is not in scope then we maybe using a constructor from a different template specialization
if (!precedes(scope->bodyStart, func.tokenDef)) if (!precedes(scope->bodyStart, func.tokenDef))
@ -276,9 +279,11 @@ void CheckClass::constructors()
func.functionScope->bodyStart->link() == func.functionScope->bodyStart->next()) { func.functionScope->bodyStart->link() == func.functionScope->bodyStart->next()) {
// don't warn about user defined default constructor when there are other constructors // don't warn about user defined default constructor when there are other constructors
if (printInconclusive) if (printInconclusive)
uninitVarError(func.token, func.access == AccessControl::Private, func.type, var.scope()->className, var.name(), derived, true); uninitVarError(func.token, func.access == AccessControl::Private, var.scope()->className, var.name(), derived, true);
} else } else if (missingCopy)
uninitVarError(func.token, func.access == AccessControl::Private, func.type, var.scope()->className, var.name(), derived, inconclusive); missingMemberCopyError(func.token, var.scope()->className, var.name());
else
uninitVarError(func.token, func.access == AccessControl::Private, var.scope()->className, var.name(), derived, false);
} }
} }
} }
@ -980,19 +985,25 @@ void CheckClass::noExplicitConstructorError(const Token *tok, const std::string
reportError(tok, Severity::style, "noExplicitConstructor", "$symbol:" + classname + '\n' + message + '\n' + verbose, CWE398, Certainty::normal); reportError(tok, Severity::style, "noExplicitConstructor", "$symbol:" + classname + '\n' + message + '\n' + verbose, CWE398, Certainty::normal);
} }
void CheckClass::uninitVarError(const Token *tok, bool isprivate, Function::Type functionType, const std::string &classname, const std::string &varname, bool derived, bool inconclusive) void CheckClass::uninitVarError(const Token *tok, bool isprivate, const std::string &classname, const std::string &varname, bool derived, bool inconclusive)
{ {
std::string message; std::string message;
if ((functionType == Function::eCopyConstructor || functionType == Function::eMoveConstructor) && inconclusive) message = "Member variable '$symbol' is not initialized in the constructor.";
message = "Member variable '$symbol' is not assigned in the copy constructor. Should it be copied?";
else
message = "Member variable '$symbol' is not initialized in the constructor.";
if (derived) if (derived)
message += " Maybe it should be initialized directly in the class " + classname + "?"; message += " Maybe it should be initialized directly in the class " + classname + "?";
std::string id = std::string("uninit") + (derived ? "Derived" : "") + "MemberVar" + (isprivate ? "Private" : ""); std::string id = std::string("uninit") + (derived ? "Derived" : "") + "MemberVar" + (isprivate ? "Private" : "");
reportError(tok, Severity::warning, id, "$symbol:" + classname + "::" + varname + "\n" + message, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal); reportError(tok, Severity::warning, id, "$symbol:" + classname + "::" + varname + "\n" + message, CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);
} }
void CheckClass::missingMemberCopyError(const Token *tok, const std::string& classname, const std::string& varname)
{
const std::string message =
"$symbol:" + classname + "::" + varname + "\n" +
"Member variable '$symbol' is not assigned in the copy constructor. Should it be copied?";
const char id[] = "missingMemberCopy";
reportError(tok, Severity::warning, id, message, CWE398, Certainty::inconclusive);
}
void CheckClass::operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive) void CheckClass::operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive)
{ {
reportError(tok, Severity::warning, "operatorEqVarError", "$symbol:" + classname + "::" + varname + "\nMember variable '$symbol' is not assigned a value in '" + classname + "::operator='.", CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal); reportError(tok, Severity::warning, "operatorEqVarError", "$symbol:" + classname + "::" + varname + "\nMember variable '$symbol' is not assigned a value in '" + classname + "::operator='.", CWE398, inconclusive ? Certainty::inconclusive : Certainty::normal);

View File

@ -199,7 +199,8 @@ private:
void noCopyConstructorError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive); void noCopyConstructorError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive);
void noOperatorEqError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive); void noOperatorEqError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive);
void noDestructorError(const Scope *scope, bool isdefault, const Token *alloc); void noDestructorError(const Scope *scope, bool isdefault, const Token *alloc);
void uninitVarError(const Token *tok, bool isprivate, Function::Type functionType, const std::string &classname, const std::string &varname, bool derived, bool inconclusive); void uninitVarError(const Token *tok, bool isprivate, const std::string &classname, const std::string &varname, bool derived, bool inconclusive);
void missingMemberCopyError(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 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);
@ -236,10 +237,11 @@ private:
c.noCopyConstructorError(nullptr, false, nullptr, false); c.noCopyConstructorError(nullptr, false, nullptr, false);
c.noOperatorEqError(nullptr, false, nullptr, false); c.noOperatorEqError(nullptr, false, nullptr, false);
c.noDestructorError(nullptr, false, nullptr); c.noDestructorError(nullptr, false, nullptr);
c.uninitVarError(nullptr, false, Function::eConstructor, "classname", "varname", false, false); c.uninitVarError(nullptr, false, "classname", "varname", false, false);
c.uninitVarError(nullptr, true, Function::eConstructor, "classname", "varnamepriv", false, false); c.uninitVarError(nullptr, true, "classname", "varnamepriv", false, false);
c.uninitVarError(nullptr, false, Function::eConstructor, "classname", "varname", true, false); c.uninitVarError(nullptr, false, "classname", "varname", true, false);
c.uninitVarError(nullptr, true, Function::eConstructor, "classname", "varnamepriv", true, false); c.uninitVarError(nullptr, true, "classname", "varnamepriv", true, false);
c.missingMemberCopyError(nullptr, "classname", "varnamepriv");
c.operatorEqVarError(nullptr, "classname", emptyString, false); c.operatorEqVarError(nullptr, "classname", emptyString, false);
c.unusedPrivateFunctionError(nullptr, "classname", "funcname"); c.unusedPrivateFunctionError(nullptr, "classname", "funcname");
c.memsetError(nullptr, "memfunc", "classname", "class"); c.memsetError(nullptr, "memfunc", "classname", "class");