Cppcheck
checkclass.h
Go to the documentation of this file.
00001 /*
00002  * Cppcheck - A tool for static C/C++ code analysis
00003  * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team.
00004  *
00005  * This program is free software: you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation, either version 3 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 //---------------------------------------------------------------------------
00020 #ifndef CheckClassH
00021 #define CheckClassH
00022 //---------------------------------------------------------------------------
00023 
00024 #include "config.h"
00025 #include "check.h"
00026 
00027 class Token;
00028 class Scope;
00029 class Function;
00030 
00031 /// @addtogroup Checks
00032 /// @{
00033 
00034 
00035 /** @brief %Check classes. Uninitialized member variables, non-conforming operators, missing virtual destructor, etc */
00036 class CPPCHECKLIB CheckClass : public Check {
00037 public:
00038     /** @brief This constructor is used when registering the CheckClass */
00039     CheckClass() : Check(myName()), symbolDatabase(NULL)
00040     { }
00041 
00042     /** @brief This constructor is used when running checks. */
00043     CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger);
00044 
00045     /** @brief Run checks on the normal token list */
00046     void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) {
00047         if (tokenizer->isC())
00048             return;
00049 
00050         CheckClass checkClass(tokenizer, settings, errorLogger);
00051 
00052         // can't be a simplified check .. the 'sizeof' is used.
00053         checkClass.noMemset();
00054     }
00055 
00056     /** @brief Run checks on the simplified token list */
00057     void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) {
00058         if (tokenizer->isC())
00059             return;
00060 
00061         CheckClass checkClass(tokenizer, settings, errorLogger);
00062 
00063         // Coding style checks
00064         checkClass.constructors();
00065         checkClass.operatorEq();
00066         checkClass.privateFunctions();
00067         checkClass.operatorEqRetRefThis();
00068         checkClass.thisSubtraction();
00069         checkClass.operatorEqToSelf();
00070         checkClass.initializerListOrder();
00071         checkClass.initializationListUsage();
00072 
00073         checkClass.virtualDestructor();
00074         checkClass.checkConst();
00075         checkClass.copyconstructors();
00076     }
00077 
00078 
00079     /** @brief %Check that all class constructors are ok */
00080     void constructors();
00081 
00082     /** @brief %Check that all private functions are called */
00083     void privateFunctions();
00084 
00085     /**
00086      * @brief %Check that the memsets are valid.
00087      * The 'memset' function can do dangerous things if used wrong. If it
00088      * is used on STL containers for instance it will clear all its data
00089      * and then the STL container may leak memory or worse have an invalid state.
00090      * It can also overwrite the virtual table.
00091      * Important: The checking doesn't work on simplified tokens list.
00092      */
00093     void noMemset();
00094     void checkMemsetType(const Scope *start, const Token *tok, const Scope *type, bool allocation);
00095 
00096     /** @brief 'operator=' should return something and it should not be const. */
00097     void operatorEq();
00098 
00099     /** @brief 'operator=' should return reference to *this */
00100     void operatorEqRetRefThis();    // Warning upon no "return *this;"
00101 
00102     /** @brief 'operator=' should check for assignment to self */
00103     void operatorEqToSelf();    // Warning upon no check for assignment to self
00104 
00105     /** @brief The destructor in a base class should be virtual */
00106     void virtualDestructor();
00107 
00108     /** @brief warn for "this-x". The indented code may be "this->x"  */
00109     void thisSubtraction();
00110 
00111     /** @brief can member function be const? */
00112     void checkConst();
00113 
00114     /** @brief Check initializer list order */
00115     void initializerListOrder();
00116 
00117     void initializationListUsage();
00118 
00119     void copyconstructors();
00120 
00121 private:
00122     const SymbolDatabase *symbolDatabase;
00123 
00124     // Reporting errors..
00125     void noConstructorError(const Token *tok, const std::string &classname, bool isStruct);
00126     //void copyConstructorMallocError(const Token *cctor, const Token *alloc, const std::string& var_name);
00127     void copyConstructorShallowCopyError(const Token *tok, const std::string& varname);
00128     void noCopyConstructorError(const Token *tok, const std::string &classname, bool isStruct);
00129     void uninitVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive);
00130     void operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive);
00131     void unusedPrivateFunctionError(const Token *tok, const std::string &classname, const std::string &funcname);
00132     void memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type);
00133     void mallocOnClassError(const Token* tok, const std::string &memfunc, const Token* classTok, const std::string &classname);
00134     void mallocOnClassWarning(const Token* tok, const std::string &memfunc, const Token* classTok);
00135     void operatorEqReturnError(const Token *tok, const std::string &className);
00136     void virtualDestructorError(const Token *tok, const std::string &Base, const std::string &Derived);
00137     void thisSubtractionError(const Token *tok);
00138     void operatorEqRetRefThisError(const Token *tok);
00139     void operatorEqToSelfError(const Token *tok);
00140     void checkConstError(const Token *tok, const std::string &classname, const std::string &funcname, bool suggestStatic);
00141     void checkConstError2(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &funcname, bool suggestStatic);
00142     void initializerListError(const Token *tok1,const Token *tok2, const std::string & classname, const std::string &varname);
00143     void suggestInitializationList(const Token *tok, const std::string& varname);
00144 
00145     void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
00146         CheckClass c(0, settings, errorLogger);
00147         c.noConstructorError(0, "classname", false);
00148         //c.copyConstructorMallocError(0, 0, "var");
00149         c.copyConstructorShallowCopyError(0, "var");
00150         c.noCopyConstructorError(0, "class", false);
00151         c.uninitVarError(0, "classname", "varname", false);
00152         c.operatorEqVarError(0, "classname", "", false);
00153         c.unusedPrivateFunctionError(0, "classname", "funcname");
00154         c.memsetError(0, "memfunc", "classname", "class");
00155         c.mallocOnClassWarning(0, "malloc", 0);
00156         c.mallocOnClassError(0, "malloc", 0, "std::string");
00157         c.operatorEqReturnError(0, "class");
00158         c.virtualDestructorError(0, "Base", "Derived");
00159         c.thisSubtractionError(0);
00160         c.operatorEqRetRefThisError(0);
00161         c.operatorEqToSelfError(0);
00162         c.checkConstError(0, "class", "function", false);
00163         c.checkConstError(0, "class", "function", true);
00164         c.initializerListError(0, 0, "class", "variable");
00165         c.suggestInitializationList(0, "variable");
00166     }
00167 
00168     static std::string myName() {
00169         return "Class";
00170     }
00171 
00172     std::string classInfo() const {
00173         return "Check the code for each class.\n"
00174                "* Missing constructors and copy constructors\n"
00175                //"* Missing allocation of memory in copy constructor\n"
00176                "* Are all variables initialized by the constructors?\n"
00177                "* Are all variables assigned by 'operator='?\n"
00178                "* Warn if memset, memcpy etc are used on a class\n"
00179                "* Warn if memory for classes is allocated with malloc()\n"
00180                "* If it's a base class, check that the destructor is virtual\n"
00181                "* Are there unused private functions?\n"
00182                "* 'operator=' should return reference to self\n"
00183                "* 'operator=' should check for assignment to self\n"
00184                "* Constness for member functions\n"
00185                "* Order of initializations\n"
00186                "* Suggest usage of initialization list\n"
00187                "* Suspicious subtraction from 'this'\n";
00188     }
00189 
00190     // operatorEqRetRefThis helper function
00191     void checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last);
00192 
00193     // operatorEqToSelf helper functions
00194     bool hasAllocation(const Function *func, const Scope* scope);
00195     static bool hasAssignSelf(const Function *func, const Token *rhs);
00196 
00197     // checkConst helper functions
00198     bool isMemberVar(const Scope *scope, const Token *tok);
00199     bool isMemberFunc(const Scope *scope, const Token *tok);
00200     bool isConstMemberFunc(const Scope *scope, const Token *tok);
00201     bool checkConstFunc(const Scope *scope, const Function *func, bool& memberAccessed);
00202 
00203     // constructors helper function
00204     /** @brief Information about a member variable. Used when checking for uninitialized variables */
00205     struct Usage {
00206         Usage() : assign(false), init(false) { }
00207 
00208         /** @brief has this variable been assigned? */
00209         bool assign;
00210 
00211         /** @brief has this variable been initialized? */
00212         bool init;
00213     };
00214 
00215     static bool isBaseClassFunc(const Token *tok, const Scope *scope);
00216 
00217     /**
00218      * @brief assign a variable in the varlist
00219      * @param varname name of variable to mark assigned
00220      * @param scope pointer to variable Scope
00221      * @param usage reference to usage vector
00222      */
00223     static void assignVar(const std::string &varname, const Scope *scope, std::vector<Usage> &usage);
00224 
00225     /**
00226      * @brief initialize a variable in the varlist
00227      * @param varname name of variable to mark initialized
00228      * @param scope pointer to variable Scope
00229      * @param usage reference to usage vector
00230      */
00231     static void initVar(const std::string &varname, const Scope *scope, std::vector<Usage> &usage);
00232 
00233     /**
00234      * @brief set all variables in list assigned
00235      * @param usage reference to usage vector
00236      */
00237     static void assignAllVar(std::vector<Usage> &usage);
00238 
00239     /**
00240      * @brief set all variables in list not assigned and not initialized
00241      * @param usage reference to usage vector
00242      */
00243     static void clearAllVar(std::vector<Usage> &usage);
00244 
00245     /**
00246      * @brief parse a scope for a constructor or member function and set the "init" flags in the provided varlist
00247      * @param func reference to the function that should be checked
00248      * @param callstack the function doesn't look into recursive function calls.
00249      * @param scope pointer to variable Scope
00250      * @param usage reference to usage vector
00251      */
00252     void initializeVarList(const Function &func, std::list<const Function *> &callstack, const Scope *scope, std::vector<Usage> &usage);
00253 
00254     static bool canNotCopy(const Scope *scope);
00255 };
00256 /// @}
00257 //---------------------------------------------------------------------------
00258 #endif