|
20 | 20 | #include "checkclass.h" |
21 | 21 |
|
22 | 22 | #include "astutils.h" |
| 23 | +#include "checkimpl.h" |
23 | 24 | #include "library.h" |
24 | 25 | #include "settings.h" |
25 | 26 | #include "standards.h" |
@@ -60,6 +61,122 @@ static const CWE CWE762(762U); // Mismatched Memory Management Routines |
60 | 61 |
|
61 | 62 | static const CWE CWE_ONE_DEFINITION_RULE(758U); |
62 | 63 |
|
| 64 | +class CheckClassImpl : public CheckImpl |
| 65 | +{ |
| 66 | +public: |
| 67 | + /** @brief This constructor is used when running checks. */ |
| 68 | + CheckClassImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger); |
| 69 | + |
| 70 | + |
| 71 | + /** @brief %Check that all class constructors are ok */ |
| 72 | + void constructors(); |
| 73 | + |
| 74 | + /** @brief %Check that constructors with single parameter are explicit, |
| 75 | + * if they has to be.*/ |
| 76 | + void checkExplicitConstructors(); |
| 77 | + |
| 78 | + /** @brief %Check that all private functions are called */ |
| 79 | + void privateFunctions(); |
| 80 | + |
| 81 | + /** |
| 82 | + * @brief %Check that the memsets are valid. |
| 83 | + * The 'memset' function can do dangerous things if used wrong. If it |
| 84 | + * is used on STL containers for instance it will clear all its data |
| 85 | + * and then the STL container may leak memory or worse have an invalid state. |
| 86 | + * It can also overwrite the virtual table. |
| 87 | + * Important: The checking doesn't work on simplified tokens list. |
| 88 | + */ |
| 89 | + void checkMemset(); |
| 90 | + void checkMemsetType(const Scope *start, const Token *tok, const Scope *type, bool allocation, std::set<const Scope *> parsedTypes); |
| 91 | + |
| 92 | + /** @brief 'operator=' should return reference to *this */ |
| 93 | + void operatorEqRetRefThis(); // Warning upon no "return *this;" |
| 94 | + |
| 95 | + /** @brief 'operator=' should check for assignment to self */ |
| 96 | + void operatorEqToSelf(); // Warning upon no check for assignment to self |
| 97 | + |
| 98 | + /** @brief The destructor in a base class should be virtual */ |
| 99 | + void virtualDestructor(); |
| 100 | + |
| 101 | + /** @brief warn for "this-x". The indented code may be "this->x" */ |
| 102 | + void thisSubtraction(); |
| 103 | + |
| 104 | + /** @brief can member function be const? */ |
| 105 | + void checkConst(); |
| 106 | + |
| 107 | + /** @brief Check initializer list order */ |
| 108 | + void initializerListOrder(); |
| 109 | + |
| 110 | + /** @brief Suggest using initialization list */ |
| 111 | + void initializationListUsage(); |
| 112 | + |
| 113 | + /** @brief Check for initialization of a member with itself */ |
| 114 | + void checkSelfInitialization(); |
| 115 | + |
| 116 | + void copyconstructors(); |
| 117 | + |
| 118 | + /** @brief call of virtual function in constructor/destructor */ |
| 119 | + void checkVirtualFunctionCallInConstructor(); |
| 120 | + |
| 121 | + /** @brief Check duplicated inherited members */ |
| 122 | + void checkDuplInheritedMembers(); |
| 123 | + |
| 124 | + /** @brief Check that copy constructor and operator defined together */ |
| 125 | + void checkCopyCtorAndEqOperator(); |
| 126 | + |
| 127 | + /** @brief Check that the override keyword is used when overriding virtual functions */ |
| 128 | + void checkOverride(); |
| 129 | + |
| 130 | + /** @brief Check that the overriden function is not identical to the base function */ |
| 131 | + void checkUselessOverride(); |
| 132 | + |
| 133 | + /** @brief When "self pointer" is destroyed, 'this' might become invalid. */ |
| 134 | + void checkThisUseAfterFree(); |
| 135 | + |
| 136 | + /** @brief Unsafe class check - const reference member */ |
| 137 | + void checkUnsafeClassRefMember(); |
| 138 | + |
| 139 | + void noConstructorError(const Token *tok, const std::string &classname, bool isStruct); |
| 140 | + void noExplicitConstructorError(const Token *tok, const std::string &classname, bool isStruct); |
| 141 | + //void copyConstructorMallocError(const Token *cctor, const Token *alloc, const std::string& var_name); |
| 142 | + void copyConstructorShallowCopyError(const Token *tok, const std::string& varname); |
| 143 | + void noCopyConstructorError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive); |
| 144 | + void noOperatorEqError(const Scope *scope, bool isdefault, const Token *alloc, bool inconclusive); |
| 145 | + void noDestructorError(const Scope *scope, bool isdefault, const Token *alloc); |
| 146 | + void uninitVarError(const Token *tok, bool isprivate, Function::Type functionType, const std::string &classname, const std::string &varname, bool derived, bool inconclusive); |
| 147 | + void uninitVarError(const Token *tok, const std::string &classname, const std::string &varname); |
| 148 | + void missingMemberCopyError(const Token *tok, Function::Type functionType, const std::string& classname, const std::string& varname); |
| 149 | + void operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive); |
| 150 | + void unusedPrivateFunctionError(const Token *tok, const std::string &classname, const std::string &funcname); |
| 151 | + void memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type, bool isContainer = false); |
| 152 | + void memsetErrorReference(const Token *tok, const std::string &memfunc, const std::string &type); |
| 153 | + void memsetErrorFloat(const Token *tok, const std::string &type); |
| 154 | + void mallocOnClassError(const Token* tok, const std::string &memfunc, const Token* classTok, const std::string &classname); |
| 155 | + void mallocOnClassWarning(const Token* tok, const std::string &memfunc, const Token* classTok); |
| 156 | + void virtualDestructorError(const Token *tok, const std::string &Base, const std::string &Derived, bool inconclusive); |
| 157 | + void thisSubtractionError(const Token *tok); |
| 158 | + void operatorEqRetRefThisError(const Token *tok); |
| 159 | + void operatorEqShouldBeLeftUnimplementedError(const Token *tok); |
| 160 | + void operatorEqMissingReturnStatementError(const Token *tok, bool error); |
| 161 | + void operatorEqToSelfError(const Token *tok); |
| 162 | + void checkConstError(const Token *tok, const std::string &classname, const std::string &funcname, bool suggestStatic); |
| 163 | + void checkConstError2(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &funcname, bool suggestStatic); |
| 164 | + void initializerListError(const Token *tok1,const Token *tok2, const std::string & classname, const std::string &varname); |
| 165 | + void suggestInitializationList(const Token *tok, const std::string& varname); |
| 166 | + void selfInitializationError(const Token* tok, const std::string& varname); |
| 167 | + void pureVirtualFunctionCallInConstructorError(const Function * scopeFunction, const std::list<const Token *> & tokStack, const std::string &purefuncname); |
| 168 | + void virtualFunctionCallInConstructorError(const Function * scopeFunction, const std::list<const Token *> & tokStack, const std::string &funcname); |
| 169 | + void duplInheritedMembersError(const Token* tok1, const Token* tok2, const std::string &derivedName, const std::string &baseName, const std::string &memberName, bool derivedIsStruct, bool baseIsStruct, bool isFunction = false); |
| 170 | + void copyCtorAndEqOperatorError(const Token *tok, const std::string &classname, bool isStruct, bool hasCopyCtor); |
| 171 | + void overrideError(const Function *funcInBase, const Function *funcInDerived); |
| 172 | + void uselessOverrideError(const Function *funcInBase, const Function *funcInDerived, bool isSameCode = false); |
| 173 | + void thisUseAfterFree(const Token *self, const Token *free, const Token *use); |
| 174 | + void unsafeClassRefMemberError(const Token *tok, const std::string &varname); |
| 175 | + void checkDuplInheritedMembersRecursive(const Type* typeCurrent, const Type* typeBase); |
| 176 | + |
| 177 | + const SymbolDatabase* mSymbolDatabase{}; |
| 178 | +}; |
| 179 | + |
63 | 180 | static const char * getFunctionTypeName(Function::Type type) |
64 | 181 | { |
65 | 182 | switch (type) { |
@@ -115,16 +232,16 @@ static bool isVclTypeInit(const Type *type) |
115 | 232 | } |
116 | 233 | //--------------------------------------------------------------------------- |
117 | 234 |
|
118 | | -CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) |
119 | | - : Check(myName(), tokenizer, settings, errorLogger), |
| 235 | +CheckClassImpl::CheckClassImpl(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) |
| 236 | + : CheckImpl(tokenizer, settings, errorLogger), |
120 | 237 | mSymbolDatabase(tokenizer?tokenizer->getSymbolDatabase():nullptr) |
121 | 238 | {} |
122 | 239 |
|
123 | 240 | //--------------------------------------------------------------------------- |
124 | 241 | // ClassCheck: Check that all class constructors are ok. |
125 | 242 | //--------------------------------------------------------------------------- |
126 | 243 |
|
127 | | -void CheckClass::constructors() |
| 244 | +void CheckClassImpl::constructors() |
128 | 245 | { |
129 | 246 | const bool printStyle = mSettings->severity.isEnabled(Severity::style); |
130 | 247 | const bool printWarnings = mSettings->severity.isEnabled(Severity::warning); |
@@ -3503,4 +3620,74 @@ bool CheckClass::analyseWholeProgram(const CTU::FileInfo *ctu, const std::list<C |
3503 | 3620 | return foundErrors; |
3504 | 3621 | } |
3505 | 3622 |
|
| 3623 | +void CheckClass::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) |
| 3624 | +{ |
| 3625 | + if (tokenizer.isC()) |
| 3626 | + return; |
3506 | 3627 |
|
| 3628 | + CheckClassImpl checkClass(&tokenizer, tokenizer.getSettings(), errorLogger); |
| 3629 | + |
| 3630 | + // can't be a simplified check .. the 'sizeof' is used. |
| 3631 | + checkClass.checkMemset(); |
| 3632 | + checkClass.constructors(); |
| 3633 | + checkClass.privateFunctions(); |
| 3634 | + checkClass.operatorEqRetRefThis(); |
| 3635 | + checkClass.thisSubtraction(); |
| 3636 | + checkClass.operatorEqToSelf(); |
| 3637 | + checkClass.initializerListOrder(); |
| 3638 | + checkClass.initializationListUsage(); |
| 3639 | + checkClass.checkSelfInitialization(); |
| 3640 | + checkClass.virtualDestructor(); |
| 3641 | + checkClass.checkConst(); |
| 3642 | + checkClass.copyconstructors(); |
| 3643 | + checkClass.checkVirtualFunctionCallInConstructor(); |
| 3644 | + checkClass.checkDuplInheritedMembers(); |
| 3645 | + checkClass.checkExplicitConstructors(); |
| 3646 | + checkClass.checkCopyCtorAndEqOperator(); |
| 3647 | + checkClass.checkOverride(); |
| 3648 | + checkClass.checkUselessOverride(); |
| 3649 | + checkClass.checkThisUseAfterFree(); |
| 3650 | + checkClass.checkUnsafeClassRefMember(); |
| 3651 | +} |
| 3652 | + |
| 3653 | +void CheckClass::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const |
| 3654 | +{ |
| 3655 | + CheckClassImpl c(nullptr, settings, errorLogger); |
| 3656 | + c.noConstructorError(nullptr, "classname", false); |
| 3657 | + c.noExplicitConstructorError(nullptr, "classname", false); |
| 3658 | + //c.copyConstructorMallocError(nullptr, 0, "var"); |
| 3659 | + c.copyConstructorShallowCopyError(nullptr, "var"); |
| 3660 | + c.noCopyConstructorError(nullptr, false, nullptr, false); |
| 3661 | + c.noOperatorEqError(nullptr, false, nullptr, false); |
| 3662 | + c.noDestructorError(nullptr, false, nullptr); |
| 3663 | + c.uninitVarError(nullptr, false, Function::eConstructor, "classname", "varname", false, false); |
| 3664 | + c.uninitVarError(nullptr, true, Function::eConstructor, "classname", "varnamepriv", false, false); |
| 3665 | + c.uninitVarError(nullptr, false, Function::eConstructor, "classname", "varname", true, false); |
| 3666 | + c.uninitVarError(nullptr, true, Function::eConstructor, "classname", "varnamepriv", true, false); |
| 3667 | + c.missingMemberCopyError(nullptr, Function::eConstructor, "classname", "varnamepriv"); |
| 3668 | + c.operatorEqVarError(nullptr, "classname", emptyString, false); |
| 3669 | + c.unusedPrivateFunctionError(nullptr, "classname", "funcname"); |
| 3670 | + c.memsetError(nullptr, "memfunc", "classname", "class"); |
| 3671 | + c.memsetErrorReference(nullptr, "memfunc", "class"); |
| 3672 | + c.memsetErrorFloat(nullptr, "class"); |
| 3673 | + c.mallocOnClassWarning(nullptr, "malloc", nullptr); |
| 3674 | + c.mallocOnClassError(nullptr, "malloc", nullptr, "std::string"); |
| 3675 | + c.virtualDestructorError(nullptr, "Base", "Derived", false); |
| 3676 | + c.thisSubtractionError(nullptr); |
| 3677 | + c.operatorEqRetRefThisError(nullptr); |
| 3678 | + c.operatorEqMissingReturnStatementError(nullptr, true); |
| 3679 | + c.operatorEqShouldBeLeftUnimplementedError(nullptr); |
| 3680 | + c.operatorEqToSelfError(nullptr); |
| 3681 | + c.checkConstError(nullptr, "class", "function", false); |
| 3682 | + c.checkConstError(nullptr, "class", "function", true); |
| 3683 | + c.initializerListError(nullptr, nullptr, "class", "variable"); |
| 3684 | + c.suggestInitializationList(nullptr, "variable"); |
| 3685 | + c.selfInitializationError(nullptr, "var"); |
| 3686 | + c.duplInheritedMembersError(nullptr, nullptr, "class", "class", "variable", false, false); |
| 3687 | + c.copyCtorAndEqOperatorError(nullptr, "class", false, false); |
| 3688 | + c.pureVirtualFunctionCallInConstructorError(nullptr, std::list<const Token *>(), "f"); |
| 3689 | + c.virtualFunctionCallInConstructorError(nullptr, std::list<const Token *>(), "f"); |
| 3690 | + c.overrideError(nullptr, nullptr); |
| 3691 | + c.thisUseAfterFree(nullptr, nullptr, nullptr); |
| 3692 | + c.unsafeClassRefMemberError(nullptr, "UnsafeClass::var"); |
| 3693 | +} |
0 commit comments