Cppcheck
checkclass.cpp
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 #include "checkclass.h"
00021 
00022 #include "tokenize.h"
00023 #include "token.h"
00024 #include "errorlogger.h"
00025 #include "symboldatabase.h"
00026 
00027 #include <string>
00028 #include <algorithm>
00029 #include <cctype>
00030 
00031 //---------------------------------------------------------------------------
00032 
00033 // Register CheckClass..
00034 namespace {
00035     CheckClass instance;
00036 
00037     const char * getFunctionTypeName(
00038         Function::Type type)
00039     {
00040         switch (type) {
00041         case Function::eConstructor:
00042             return "constructor";
00043         case Function::eCopyConstructor:
00044             return "copy constructor";
00045         case Function::eMoveConstructor:
00046             return "move constructor";
00047         case Function::eDestructor:
00048             return "destructor";
00049         case Function::eFunction:
00050             return "function";
00051         case Function::eOperatorEqual:
00052             return "operator=";
00053         }
00054         return "";
00055     }
00056 
00057     inline bool isPureWithoutBody(Function const & func)
00058     {
00059         return func.isPure && !func.hasBody;
00060     }
00061 }
00062 
00063 //---------------------------------------------------------------------------
00064 
00065 CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
00066     : Check(myName(), tokenizer, settings, errorLogger),
00067       symbolDatabase(tokenizer?tokenizer->getSymbolDatabase():NULL)
00068 {
00069 
00070 }
00071 
00072 //---------------------------------------------------------------------------
00073 // ClassCheck: Check that all class constructors are ok.
00074 //---------------------------------------------------------------------------
00075 
00076 void CheckClass::constructors()
00077 {
00078     bool style = _settings->isEnabled("style");
00079     bool warnings = _settings->isEnabled("warning");
00080     if (!style && !warnings)
00081         return;
00082 
00083     const std::size_t classes = symbolDatabase->classAndStructScopes.size();
00084     for (std::size_t i = 0; i < classes; ++i) {
00085         const Scope * scope = symbolDatabase->classAndStructScopes[i];
00086 
00087         // There are no constructors.
00088         if (scope->numConstructors == 0 && style) {
00089             // If there is a private variable, there should be a constructor..
00090             std::list<Variable>::const_iterator var;
00091             for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) {
00092                 if (var->isPrivate() && !var->isStatic() &&
00093                     (!var->isClass() || (var->type() && var->type()->needInitialization == Type::True))) {
00094                     noConstructorError(scope->classDef, scope->className, scope->classDef->str() == "struct");
00095                     break;
00096                 }
00097             }
00098         }
00099 
00100         if (!warnings)
00101             continue;
00102 
00103         // #3196 => bailout if there are nested unions
00104         // TODO: handle union variables better
00105         {
00106             bool bailout = false;
00107             for (std::list<Scope *>::const_iterator it = scope->nestedList.begin(); it != scope->nestedList.end(); ++it) {
00108                 const Scope * const nestedScope = *it;
00109                 if (nestedScope->type == Scope::eUnion) {
00110                     bailout = true;
00111                     break;
00112                 }
00113             }
00114             if (bailout)
00115                 continue;
00116         }
00117 
00118 
00119         std::list<Function>::const_iterator func;
00120         std::vector<Usage> usage(scope->varlist.size());
00121 
00122         for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
00123             if (!func->hasBody || !(func->isConstructor() ||
00124                                     func->type == Function::eOperatorEqual))
00125                 continue;
00126 
00127             // Mark all variables not used
00128             clearAllVar(usage);
00129 
00130             std::list<const Function *> callstack;
00131             initializeVarList(*func, callstack, &(*scope), usage);
00132 
00133             // Check if any variables are uninitialized
00134             std::list<Variable>::const_iterator var;
00135             unsigned int count = 0;
00136             for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var, ++count) {
00137                 // check for C++11 initializer
00138                 if (var->hasDefault())
00139                     usage[count].init = true;
00140 
00141                 bool inconclusive = false;
00142 
00143                 if (usage[count].assign || usage[count].init || var->isStatic())
00144                     continue;
00145 
00146                 if (var->isConst() && func->isOperator) // We can't set const members in assignment operator
00147                     continue;
00148 
00149                 // Check if this is a class constructor
00150                 if (!var->isPointer() && var->isClass() && func->type == Function::eConstructor) {
00151                     // Unknown type so assume it is initialized
00152                     if (!var->type())
00153                         continue;
00154 
00155                     // Known type that doesn't need initialization or
00156                     // known type that has member variables of an unknown type
00157                     else if (var->type()->needInitialization != Type::True)
00158                         continue;
00159                 }
00160 
00161                 // Check if type can't be copied
00162                 if (!var->isPointer() && var->typeScope()) {
00163                     if (func->type == Function::eMoveConstructor) {
00164                         if (canNotMove(var->typeScope()))
00165                             continue;
00166                     } else {
00167                         if (canNotCopy(var->typeScope()))
00168                             continue;
00169                     }
00170                 }
00171 
00172                 // Don't warn about unknown types in copy constructors since we
00173                 // don't know if they can be copied or not..
00174                 if (!var->isPointer() &&
00175                     !(var->type() && var->type()->needInitialization != Type::True) &&
00176                     (func->type == Function::eCopyConstructor || func->type == Function::eOperatorEqual)) {
00177                     bool stdtype = false;
00178                     for (const Token *type = var->typeStartToken(); type && type->isName(); type = type->next())
00179                         stdtype |= type->isStandardType();
00180                     if (!stdtype) {
00181                         if (_settings->inconclusive)
00182                             inconclusive = true;
00183                         else
00184                             continue;
00185                     }
00186                 }
00187 
00188                 // It's non-static and it's not initialized => error
00189                 if (func->type == Function::eOperatorEqual) {
00190                     const Token *operStart = func->arg;
00191 
00192                     bool classNameUsed = false;
00193                     for (const Token *operTok = operStart; operTok != operStart->link(); operTok = operTok->next()) {
00194                         if (operTok->str() == scope->className) {
00195                             classNameUsed = true;
00196                             break;
00197                         }
00198                     }
00199 
00200                     if (classNameUsed)
00201                         operatorEqVarError(func->token, scope->className, var->name(), inconclusive);
00202                 } else if (func->access != Private) {
00203                     const Scope *varType = var->typeScope();
00204                     if (!varType || varType->type != Scope::eUnion) {
00205                         if (func->type == Function::eConstructor &&
00206                             func->nestedIn && (func->nestedIn->numConstructors - func->nestedIn->numCopyOrMoveConstructors) > 1 &&
00207                             func->argCount() == 0 && func->functionScope &&
00208                             func->arg && func->arg->link()->next() == func->functionScope->classStart &&
00209                             func->functionScope->classStart->link() == func->functionScope->classStart->next()) {
00210                             // don't warn about user defined default constructor when there are other constructors
00211                             if (_settings->inconclusive)
00212                                 uninitVarError(func->token, scope->className, var->name(), true);
00213                         } else
00214                             uninitVarError(func->token, scope->className, var->name(), inconclusive);
00215                     }
00216                 }
00217             }
00218         }
00219     }
00220 }
00221 
00222 void CheckClass::copyconstructors()
00223 {
00224     if (!_settings->isEnabled("style"))
00225         return;
00226 
00227     const std::size_t classes = symbolDatabase->classAndStructScopes.size();
00228     for (std::size_t i = 0; i < classes; ++i) {
00229         const Scope * scope = symbolDatabase->classAndStructScopes[i];
00230         std::map<unsigned int, const Token*> allocatedVars;
00231 
00232         for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
00233             if (func->type == Function::eConstructor && func->functionScope) {
00234                 const Token* tok = func->functionScope->classDef->linkAt(1);
00235                 for (const Token* const end = func->functionScope->classStart; tok != end; tok = tok->next()) {
00236                     if (Token::Match(tok, "%var% ( new|malloc|g_malloc|g_try_malloc|realloc|g_realloc|g_try_realloc")) {
00237                         const Variable* var = tok->variable();
00238                         if (var && var->isPointer() && var->scope() == &*scope)
00239                             allocatedVars[tok->varId()] = tok;
00240                     }
00241                 }
00242                 for (const Token* const end = func->functionScope->classEnd; tok != end; tok = tok->next()) {
00243                     if (Token::Match(tok, "%var% = new|malloc|g_malloc|g_try_malloc|realloc|g_realloc|g_try_realloc")) {
00244                         const Variable* var = tok->variable();
00245                         if (var && var->isPointer() && var->scope() == &*scope)
00246                             allocatedVars[tok->varId()] = tok;
00247                     }
00248                 }
00249             }
00250         }
00251 
00252         std::set<const Token*> copiedVars;
00253         const Token* copyCtor = 0;
00254         for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
00255             if (func->type == Function::eCopyConstructor) {
00256                 copyCtor = func->tokenDef;
00257                 if (func->functionScope) {
00258                     const Token* tok = func->tokenDef->linkAt(1)->next();
00259                     if (tok->str()==":") {
00260                         tok=tok->next();
00261                         while (Token::Match(tok, "%var% (")) {
00262                             if (allocatedVars.find(tok->varId()) != allocatedVars.end()) {
00263                                 if (tok->varId() && Token::Match(tok->tokAt(2), "%var% . %var% )"))
00264                                     copiedVars.insert(tok);
00265                                 else if (!Token::Match(tok->tokAt(2), "%any% )"))
00266                                     allocatedVars.erase(tok->varId()); // Assume memory is allocated
00267                             }
00268                             tok = tok->linkAt(1)->tokAt(2);
00269                         }
00270                     }
00271                     for (tok=func->functionScope->classStart; tok!=func->functionScope->classEnd; tok=tok->next()) {
00272                         if (Token::Match(tok, "%var% = new|malloc|g_malloc|g_try_malloc|realloc|g_realloc|g_try_realloc")) {
00273                             allocatedVars.erase(tok->varId());
00274                         } else if (Token::Match(tok, "%var% = %var% . %var% ;") && allocatedVars.find(tok->varId()) != allocatedVars.end()) {
00275                             copiedVars.insert(tok);
00276                         }
00277                     }
00278                 } else // non-copyable or implementation not seen
00279                     allocatedVars.clear();
00280                 break;
00281             }
00282         }
00283         if (!copyCtor) {
00284             if (!allocatedVars.empty() && scope->definedType->derivedFrom.empty()) // TODO: Check if base class is non-copyable
00285                 noCopyConstructorError(scope->classDef, scope->className, scope->type == Scope::eStruct);
00286         } else {
00287             if (!copiedVars.empty()) {
00288                 for (std::set<const Token*>::const_iterator it = copiedVars.begin(); it != copiedVars.end(); ++it) {
00289                     copyConstructorShallowCopyError(*it, (*it)->str());
00290                 }
00291             }
00292             // throw error if count mismatch
00293             /* FIXME: This doesn't work. See #4154
00294             for (std::map<unsigned int, const Token*>::const_iterator i = allocatedVars.begin(); i != allocatedVars.end(); ++i) {
00295                 copyConstructorMallocError(copyCtor, i->second, i->second->str());
00296             }
00297             */
00298         }
00299     }
00300 }
00301 
00302 /* This doesn't work. See #4154
00303 void CheckClass::copyConstructorMallocError(const Token *cctor, const Token *alloc, const std::string& varname)
00304 {
00305     std::list<const Token*> callstack;
00306     callstack.push_back(cctor);
00307     callstack.push_back(alloc);
00308     reportError(callstack, Severity::warning, "copyCtorNoAllocation", "Copy constructor does not allocate memory for member '" + varname + "' although memory has been allocated in other constructors.");
00309 }
00310 */
00311 
00312 void CheckClass::copyConstructorShallowCopyError(const Token *tok, const std::string& varname)
00313 {
00314     reportError(tok, Severity::style, "copyCtorPointerCopying", "Value of pointer '" + varname + "', which points to allocated memory, is copied in copy constructor instead of allocating new memory.");
00315 }
00316 
00317 void CheckClass::noCopyConstructorError(const Token *tok, const std::string &classname, bool isStruct)
00318 {
00319     // The constructor might be intentionally missing. Therefore this is not a "warning"
00320     reportError(tok, Severity::style, "noCopyConstructor",
00321                 "'" + std::string(isStruct ? "struct" : "class") + " " + classname +
00322                 "' does not have a copy constructor which is recommended since the class contains a pointer to allocated memory.");
00323 }
00324 
00325 bool CheckClass::canNotCopy(const Scope *scope)
00326 {
00327     std::list<Function>::const_iterator func;
00328     bool constructor = false;
00329     bool publicAssign = false;
00330     bool publicCopy = false;
00331 
00332     for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
00333         if (func->isConstructor())
00334             constructor = true;
00335         if ((func->type == Function::eCopyConstructor) &&
00336             func->access == Public)
00337             publicCopy = true;
00338         else if (func->type == Function::eOperatorEqual && func->access == Public)
00339             publicAssign = true;
00340     }
00341 
00342     return constructor && !(publicAssign || publicCopy);
00343 }
00344 
00345 bool CheckClass::canNotMove(const Scope *scope)
00346 {
00347     std::list<Function>::const_iterator func;
00348     bool constructor = false;
00349     bool publicAssign = false;
00350     bool publicCopy = false;
00351     bool publicMove = false;
00352 
00353     for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
00354         if (func->isConstructor())
00355             constructor = true;
00356         if ((func->type == Function::eCopyConstructor) &&
00357             func->access == Public)
00358             publicCopy = true;
00359         else if ((func->type == Function::eMoveConstructor) &&
00360                  func->access == Public)
00361             publicMove = true;
00362         else if (func->type == Function::eOperatorEqual && func->access == Public)
00363             publicAssign = true;
00364     }
00365 
00366     return constructor && !(publicAssign || publicCopy || publicMove);
00367 }
00368 
00369 void CheckClass::assignVar(const std::string &varname, const Scope *scope, std::vector<Usage> &usage)
00370 {
00371     std::list<Variable>::const_iterator var;
00372     unsigned int count = 0;
00373 
00374     for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var, ++count) {
00375         if (var->name() == varname) {
00376             usage[count].assign = true;
00377             return;
00378         }
00379     }
00380 }
00381 
00382 void CheckClass::initVar(const std::string &varname, const Scope *scope, std::vector<Usage> &usage)
00383 {
00384     std::list<Variable>::const_iterator var;
00385     unsigned int count = 0;
00386 
00387     for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var, ++count) {
00388         if (var->name() == varname) {
00389             usage[count].init = true;
00390             return;
00391         }
00392     }
00393 }
00394 
00395 void CheckClass::assignAllVar(std::vector<Usage> &usage)
00396 {
00397     for (std::size_t i = 0; i < usage.size(); ++i)
00398         usage[i].assign = true;
00399 }
00400 
00401 void CheckClass::clearAllVar(std::vector<Usage> &usage)
00402 {
00403     for (std::size_t i = 0; i < usage.size(); ++i) {
00404         usage[i].assign = false;
00405         usage[i].init = false;
00406     }
00407 }
00408 
00409 bool CheckClass::isBaseClassFunc(const Token *tok, const Scope *scope)
00410 {
00411     // Iterate through each base class...
00412     for (std::size_t i = 0; i < scope->definedType->derivedFrom.size(); ++i) {
00413         const Type *derivedFrom = scope->definedType->derivedFrom[i].type;
00414 
00415         // Check if base class exists in database
00416         if (derivedFrom && derivedFrom->classScope) {
00417             std::list<Function>::const_iterator func;
00418 
00419             for (func = derivedFrom->classScope->functionList.begin(); func != derivedFrom->classScope->functionList.end(); ++func) {
00420                 if (func->tokenDef->str() == tok->str())
00421                     return true;
00422             }
00423         }
00424 
00425         // Base class not found so assume it is in it.
00426         else
00427             return true;
00428     }
00429 
00430     return false;
00431 }
00432 
00433 void CheckClass::initializeVarList(const Function &func, std::list<const Function *> &callstack, const Scope *scope, std::vector<Usage> &usage)
00434 {
00435     bool initList = func.isConstructor();
00436     const Token *ftok = func.arg->link()->next();
00437     int level = 0;
00438     for (; ftok != func.functionScope->classEnd; ftok = ftok->next()) {
00439         // Class constructor.. initializing variables like this
00440         // clKalle::clKalle() : var(value) { }
00441         if (initList) {
00442             if (level == 0 && Token::Match(ftok, "%var% (")) {
00443                 if (ftok->str() != func.name()) {
00444                     initVar(ftok->str(), scope, usage);
00445                 } else { // c++11 delegate constructor
00446                     const Function *member = scope->findFunction(ftok);
00447                     // member function found
00448                     if (member) {
00449                         // recursive call
00450                         // assume that all variables are initialized
00451                         if (std::find(callstack.begin(), callstack.end(), member) != callstack.end()) {
00452                             /** @todo false negative: just bail */
00453                             assignAllVar(usage);
00454                             return;
00455                         }
00456 
00457                         // member function has implementation
00458                         if (member->hasBody) {
00459                             // initialize variable use list using member function
00460                             callstack.push_back(member);
00461                             initializeVarList(*member, callstack, scope, usage);
00462                             callstack.pop_back();
00463                         }
00464 
00465                         // there is a called member function, but it has no implementation, so we assume it initializes everything
00466                         else {
00467                             assignAllVar(usage);
00468                         }
00469                     }
00470                 }
00471             } else if (level == 0 && Token::Match(ftok, "%var% {") && ftok->str() != "const" && Token::Match(ftok->next()->link()->next(), ",|{|%type%")) {
00472                 initVar(ftok->str(), scope, usage);
00473                 ftok = ftok->linkAt(1);
00474             } else if (level != 0 && Token::Match(ftok, "%var% =")) // assignment in the initializer: var(value = x)
00475                 assignVar(ftok->str(), scope, usage);
00476 
00477             else if (ftok->str() == "(")
00478                 level++;
00479             else if (ftok->str() == ")")
00480                 level--;
00481             else if (ftok->str() == "{") {
00482                 if (level == 0)
00483                     initList = false;
00484                 else
00485                     ftok = ftok->link();
00486             }
00487         }
00488 
00489         if (initList)
00490             continue;
00491 
00492         // Variable getting value from stream?
00493         if (Token::Match(ftok, ">> %var%")) {
00494             assignVar(ftok->strAt(1), scope, usage);
00495         }
00496 
00497         // Before a new statement there is "[{};)=]"
00498         if (! Token::Match(ftok, "[{};()=]"))
00499             continue;
00500 
00501         if (Token::simpleMatch(ftok, "( !"))
00502             ftok = ftok->next();
00503 
00504         // Using the operator= function to initialize all variables..
00505         if (Token::Match(ftok->next(), "return| (| * this )| =")) {
00506             assignAllVar(usage);
00507             break;
00508         }
00509 
00510         // Using swap to assign all variables..
00511         if (func.type == Function::eOperatorEqual && Token::Match(ftok, "[;{}] %var% (") && Token::Match(ftok->linkAt(2), ") . %var% ( *| this ) ;")) {
00512             assignAllVar(usage);
00513             break;
00514         }
00515 
00516         // Calling member variable function?
00517         if (Token::Match(ftok->next(), "%var% . %var% (")) {
00518             std::list<Variable>::const_iterator var;
00519             for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) {
00520                 if (var->varId() == ftok->next()->varId()) {
00521                     /** @todo false negative: we assume function changes variable state */
00522                     assignVar(ftok->next()->str(), scope, usage);
00523                     break;
00524                 }
00525             }
00526 
00527             ftok = ftok->tokAt(2);
00528         }
00529 
00530         if (!Token::Match(ftok->next(), "::| %var%") &&
00531             !Token::Match(ftok->next(), "this . %var%") &&
00532             !Token::Match(ftok->next(), "* %var% =") &&
00533             !Token::Match(ftok->next(), "( * this ) . %var%"))
00534             continue;
00535 
00536         // Goto the first token in this statement..
00537         ftok = ftok->next();
00538 
00539         // skip "return"
00540         if (ftok->str() == "return")
00541             ftok = ftok->next();
00542 
00543         // Skip "( * this )"
00544         if (Token::simpleMatch(ftok, "( * this ) .")) {
00545             ftok = ftok->tokAt(5);
00546         }
00547 
00548         // Skip "this->"
00549         if (Token::simpleMatch(ftok, "this ."))
00550             ftok = ftok->tokAt(2);
00551 
00552         // Skip "classname :: "
00553         if (Token::Match(ftok, "%var% ::"))
00554             ftok = ftok->tokAt(2);
00555 
00556         // Clearing all variables..
00557         if (Token::Match(ftok, "::| memset ( this ,")) {
00558             assignAllVar(usage);
00559             return;
00560         }
00561 
00562         // Clearing array..
00563         else if (Token::Match(ftok, "::| memset ( %var% ,")) {
00564             if (ftok->str() == "::")
00565                 ftok = ftok->next();
00566             assignVar(ftok->strAt(2), scope, usage);
00567             ftok = ftok->linkAt(1);
00568             continue;
00569         }
00570 
00571         // Calling member function?
00572         else if (Token::simpleMatch(ftok, "operator= (") &&
00573                  ftok->previous()->str() != "::") {
00574             if (ftok->function() && ftok->function()->nestedIn == scope) {
00575                 const Function *member = ftok->function();
00576                 // recursive call
00577                 // assume that all variables are initialized
00578                 if (std::find(callstack.begin(), callstack.end(), member) != callstack.end()) {
00579                     /** @todo false negative: just bail */
00580                     assignAllVar(usage);
00581                     return;
00582                 }
00583 
00584                 // member function has implementation
00585                 if (member->hasBody) {
00586                     // initialize variable use list using member function
00587                     callstack.push_back(member);
00588                     initializeVarList(*member, callstack, scope, usage);
00589                     callstack.pop_back();
00590                 }
00591 
00592                 // there is a called member function, but it has no implementation, so we assume it initializes everything
00593                 else {
00594                     assignAllVar(usage);
00595                 }
00596             }
00597 
00598             // using default operator =, assume everything initialized
00599             else {
00600                 assignAllVar(usage);
00601             }
00602         } else if (Token::Match(ftok, "::| %var% (") && ftok->str() != "if") {
00603             if (ftok->str() == "::")
00604                 ftok = ftok->next();
00605 
00606             // Passing "this" => assume that everything is initialized
00607             for (const Token *tok2 = ftok->next()->link(); tok2 && tok2 != ftok; tok2 = tok2->previous()) {
00608                 if (tok2->str() == "this") {
00609                     assignAllVar(usage);
00610                     return;
00611                 }
00612             }
00613 
00614             // check if member function
00615             if (ftok->function() && ftok->function()->nestedIn == scope &&
00616                 !ftok->function()->isConstructor()) {
00617                 const Function *member = ftok->function();
00618 
00619                 // recursive call
00620                 // assume that all variables are initialized
00621                 if (std::find(callstack.begin(), callstack.end(), member) != callstack.end()) {
00622                     assignAllVar(usage);
00623                     return;
00624                 }
00625 
00626                 // member function has implementation
00627                 if (member->hasBody) {
00628                     // initialize variable use list using member function
00629                     callstack.push_back(member);
00630                     initializeVarList(*member, callstack, scope, usage);
00631                     callstack.pop_back();
00632 
00633                     // Assume that variables that are passed to it are initialized..
00634                     for (const Token *tok2 = ftok; tok2; tok2 = tok2->next()) {
00635                         if (Token::Match(tok2, "[;{}]"))
00636                             break;
00637                         if (Token::Match(tok2, "[(,] &| %var% [,)]")) {
00638                             tok2 = tok2->next();
00639                             if (tok2->str() == "&")
00640                                 tok2 = tok2->next();
00641                             assignVar(tok2->str(), scope, usage);
00642                         }
00643                     }
00644                 }
00645 
00646                 // there is a called member function, but it has no implementation, so we assume it initializes everything
00647                 else {
00648                     assignAllVar(usage);
00649                 }
00650             }
00651 
00652             // not member function
00653             else {
00654                 // could be a base class virtual function, so we assume it initializes everything
00655                 if (!func.isConstructor() && isBaseClassFunc(ftok, scope)) {
00656                     /** @todo False Negative: we should look at the base class functions to see if they
00657                      *  call any derived class virtual functions that change the derived class state
00658                      */
00659                     assignAllVar(usage);
00660                 }
00661 
00662                 // has friends, so we assume it initializes everything
00663                 if (!scope->definedType->friendList.empty())
00664                     assignAllVar(usage);
00665 
00666                 // the function is external and it's neither friend nor inherited virtual function.
00667                 // assume all variables that are passed to it are initialized..
00668                 else {
00669                     for (const Token *tok = ftok->tokAt(2); tok && tok != ftok->next()->link(); tok = tok->next()) {
00670                         if (tok->isName()) {
00671                             assignVar(tok->str(), scope, usage);
00672                         }
00673                     }
00674                 }
00675             }
00676         }
00677 
00678         // Assignment of member variable?
00679         else if (Token::Match(ftok, "%var% =")) {
00680             assignVar(ftok->str(), scope, usage);
00681         }
00682 
00683         // Assignment of array item of member variable?
00684         else if (Token::Match(ftok, "%var% [|.")) {
00685             const Token *tok2 = ftok;
00686             while (tok2) {
00687                 if (tok2->strAt(1) == "[")
00688                     tok2 = tok2->next()->link();
00689                 else if (Token::Match(tok2->next(), ". %var%"))
00690                     tok2 = tok2->tokAt(2);
00691                 else
00692                     break;
00693             }
00694             if (tok2 && tok2->strAt(1) == "=")
00695                 assignVar(ftok->str(), scope, usage);
00696         }
00697 
00698         // Assignment of array item of member variable?
00699         else if (Token::Match(ftok, "* %var% =")) {
00700             assignVar(ftok->next()->str(), scope, usage);
00701         }
00702 
00703         // The functions 'clear' and 'Clear' are supposed to initialize variable.
00704         if (Token::Match(ftok, "%var% . clear|Clear (")) {
00705             assignVar(ftok->str(), scope, usage);
00706         }
00707     }
00708 }
00709 
00710 void CheckClass::noConstructorError(const Token *tok, const std::string &classname, bool isStruct)
00711 {
00712     // For performance reasons the constructor might be intentionally missing. Therefore this is not a "warning"
00713     reportError(tok, Severity::style, "noConstructor",
00714                 "The " + std::string(isStruct ? "struct" : "class") + " '" + classname +
00715                 "' does not have a constructor.\n"
00716                 "The " + std::string(isStruct ? "struct" : "class") + " '" + classname +
00717                 "' does not have a constructor although it has private member variables. "
00718                 "Member variables of builtin types are left uninitialized when the class is "
00719                 "instanciated. That may cause bugs or undefined behavior.");
00720 }
00721 
00722 void CheckClass::uninitVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive)
00723 {
00724     reportError(tok, Severity::warning, "uninitMemberVar", "Member variable '" + classname + "::" + varname + "' is not initialized in the constructor.", inconclusive);
00725 }
00726 
00727 void CheckClass::operatorEqVarError(const Token *tok, const std::string &classname, const std::string &varname, bool inconclusive)
00728 {
00729     reportError(tok, Severity::warning, "operatorEqVarError", "Member variable '" + classname + "::" + varname + "' is not assigned a value in '" + classname + "::operator='.", inconclusive);
00730 }
00731 
00732 //---------------------------------------------------------------------------
00733 // ClassCheck: Use initialization list instead of assignment
00734 //---------------------------------------------------------------------------
00735 
00736 void CheckClass::initializationListUsage()
00737 {
00738     if (!_settings->isEnabled("performance"))
00739         return;
00740 
00741     const std::size_t functions = symbolDatabase->functionScopes.size();
00742     for (std::size_t i = 0; i < functions; ++i) {
00743         const Scope * scope = symbolDatabase->functionScopes[i];
00744 
00745         // Check every constructor
00746         if (!scope->function || (!scope->function->isConstructor()))
00747             continue;
00748 
00749         const Scope* owner = scope->functionOf;
00750         for (const Token* tok = scope->classStart; tok != scope->classEnd; tok = tok->next()) {
00751             if (Token::Match(tok, "%var% (")) // Assignments might depend on this function call or if/for/while/switch statement from now on.
00752                 break;
00753             if (Token::Match(tok, "try|do {"))
00754                 break;
00755             if (tok->varId() && Token::Match(tok, "%var% = %any%")) {
00756                 const Variable* var = tok->variable();
00757                 if (var && var->scope() == owner && !var->isStatic()) {
00758                     bool allowed = true;
00759                     for (const Token* tok2 = tok->tokAt(2); tok2->str() != ";"; tok2 = tok2->next()) {
00760                         if (tok2->varId()) {
00761                             const Variable* var2 = tok2->variable();
00762                             if (var2 && var2->scope() == owner &&
00763                                 tok2->strAt(-1)!=".") { // Is there a dependency between two member variables?
00764                                 allowed = false;
00765                                 break;
00766                             }
00767                         } else if (tok2->str() == "this") { // 'this' instance is not completely constructed in initialization list
00768                             allowed = false;
00769                             break;
00770                         } else if (Token::Match(tok2, "%var% (") && tok2->strAt(-1) != "." && isMemberFunc(owner, tok2)) { // Member function called?
00771                             allowed = false;
00772                             break;
00773                         }
00774                     }
00775                     if (!allowed)
00776                         continue;
00777                     if (!var->isPointer() && (var->type() || Token::Match(var->typeStartToken(), "std :: string|wstring !!::") || (Token::Match(var->typeStartToken(), "std :: %type% <") && !Token::simpleMatch(var->typeStartToken()->linkAt(3), "> ::"))))
00778                         suggestInitializationList(tok, tok->str());
00779                 }
00780             }
00781         }
00782     }
00783 }
00784 
00785 void CheckClass::suggestInitializationList(const Token* tok, const std::string& varname)
00786 {
00787     reportError(tok, Severity::performance, "useInitializationList", "Variable '" + varname + "' is assigned in constructor body. Consider performing initialization in initialization list.\n"
00788                 "When an object of a class is created, the constructors of all member variables are called consecutively "
00789                 "in the order the variables are declared, even if you don't explicitly write them to the initialization list. You "
00790                 "could avoid assigning '" + varname + "' a value by passing the value to the constructor in the initialization list.");
00791 }
00792 
00793 //---------------------------------------------------------------------------
00794 // ClassCheck: Unused private functions
00795 //---------------------------------------------------------------------------
00796 
00797 static bool checkFunctionUsage(const std::string& name, const Scope* scope)
00798 {
00799     if (!scope)
00800         return true; // Assume it is used, if scope is not seen
00801 
00802     for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
00803         if (func->functionScope) {
00804             for (const Token *ftok = func->functionScope->classDef->linkAt(1); ftok != func->functionScope->classEnd; ftok = ftok->next()) {
00805                 if (ftok->str() == name) // Function used. TODO: Handle overloads
00806                     return true;
00807             }
00808         } else if ((func->type != Function::eCopyConstructor &&
00809                     func->type != Function::eOperatorEqual) ||
00810                    func->access != Private) // Assume it is used, if a function implementation isn't seen, but empty private copy constructors and assignment operators are OK
00811             return true;
00812     }
00813 
00814     for (std::list<Scope*>::const_iterator i = scope->nestedList.begin(); i != scope->nestedList.end(); ++i) {
00815         if ((*i)->isClassOrStruct())
00816             if (checkFunctionUsage(name, *i)) // Check nested classes, which can access private functions of their base
00817                 return true;
00818     }
00819 
00820     return false; // Unused in this scope
00821 }
00822 
00823 void CheckClass::privateFunctions()
00824 {
00825     if (!_settings->isEnabled("style"))
00826         return;
00827 
00828     const std::size_t classes = symbolDatabase->classAndStructScopes.size();
00829     for (std::size_t i = 0; i < classes; ++i) {
00830         const Scope * scope = symbolDatabase->classAndStructScopes[i];
00831 
00832         // dont check borland classes with properties..
00833         if (Token::findsimplematch(scope->classStart, "; __property ;", scope->classEnd))
00834             continue;
00835 
00836         std::list<const Function*> FuncList;
00837         for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
00838             // Get private functions..
00839             if (func->type == Function::eFunction && func->access == Private)
00840                 FuncList.push_back(&*func);
00841         }
00842 
00843         // Bailout for overridden virtual functions of base classes
00844         if (!scope->definedType->derivedFrom.empty()) {
00845             // Check virtual functions
00846             for (std::list<const Function*>::iterator it = FuncList.begin(); it != FuncList.end();) {
00847                 if ((*it)->isImplicitlyVirtual(true)) // Give true as default value to be returned if we don't see all base classes
00848                     FuncList.erase(it++);
00849                 else
00850                     ++it;
00851             }
00852         }
00853 
00854         while (!FuncList.empty()) {
00855             const std::string& funcName = FuncList.front()->tokenDef->str();
00856             // Check that all private functions are used
00857             bool used = checkFunctionUsage(funcName, &*scope); // Usage in this class
00858             // Check in friend classes
00859             for (std::list<Type::FriendInfo>::const_iterator it = scope->definedType->friendList.begin(); !used && it != scope->definedType->friendList.end(); ++it)
00860                 if (it->type)
00861                     used = checkFunctionUsage(funcName, it->type->classScope);
00862                 else
00863                     used = true; // Assume, it is used if we do not see friend class
00864 
00865             if (!used)
00866                 unusedPrivateFunctionError(FuncList.front()->tokenDef, scope->className, funcName);
00867 
00868             FuncList.pop_front();
00869         }
00870     }
00871 }
00872 
00873 void CheckClass::unusedPrivateFunctionError(const Token *tok, const std::string &classname, const std::string &funcname)
00874 {
00875     reportError(tok, Severity::style, "unusedPrivateFunction", "Unused private function: '" + classname + "::" + funcname + "'");
00876 }
00877 
00878 //---------------------------------------------------------------------------
00879 // ClassCheck: Check that memset is not used on classes
00880 //---------------------------------------------------------------------------
00881 
00882 static const Scope* findFunctionOf(const Scope* scope)
00883 {
00884     while (scope) {
00885         if (scope->type == Scope::eFunction)
00886             return scope->functionOf;
00887         scope = scope->nestedIn;
00888     }
00889     return 0;
00890 }
00891 
00892 void CheckClass::noMemset()
00893 {
00894     const std::size_t functions = symbolDatabase->functionScopes.size();
00895     for (std::size_t i = 0; i < functions; ++i) {
00896         const Scope * scope = symbolDatabase->functionScopes[i];
00897         for (const Token *tok = scope->classStart; tok && tok != scope->classEnd; tok = tok->next()) {
00898             if (Token::Match(tok, "memset|memcpy|memmove ( %any%")) {
00899                 const Token* arg1 = tok->tokAt(2);
00900                 const Token* arg3 = arg1;
00901                 arg3 = arg3->nextArgument();
00902                 arg3 = (arg3 != NULL) ? arg3->nextArgument() : NULL;
00903                 if (!arg3)
00904                     // weird, shouldn't happen: memset etc should have
00905                     // 3 arguments.
00906                     continue;
00907 
00908                 const Token *typeTok = 0;
00909                 const Scope *type = 0;
00910                 if (Token::Match(arg3, "sizeof ( %type% ) )"))
00911                     typeTok = arg3->tokAt(2);
00912                 else if (Token::Match(arg3, "sizeof ( %type% :: %type% ) )"))
00913                     typeTok = arg3->tokAt(4);
00914                 else if (Token::Match(arg3, "sizeof ( struct %type% ) )"))
00915                     typeTok = arg3->tokAt(3);
00916                 else if (Token::simpleMatch(arg3, "sizeof ( * this ) )") || Token::simpleMatch(arg1, "this ,")) {
00917                     type = findFunctionOf(arg3->scope());
00918                 } else if (Token::Match(arg1, "&|*|%var%")) {
00919                     int derefs = 1;
00920                     for (;; arg1 = arg1->next()) {
00921                         if (arg1->str() == "&")
00922                             derefs--;
00923                         else if (arg1->str() == "*")
00924                             derefs++;
00925                         else
00926                             break;
00927                     }
00928 
00929                     const Variable *var = arg1->variable();
00930                     if (var && arg1->strAt(1) == ",") {
00931                         if (var->isPointer())
00932                             derefs--;
00933                         if (var->isArray())
00934                             derefs -= (int)var->dimensions().size();
00935 
00936                         if (derefs == 0)
00937                             type = var->typeScope();
00938                     }
00939                 }
00940 
00941                 // No type defined => The tokens didn't match
00942                 if (!typeTok && !type)
00943                     continue;
00944 
00945                 if (typeTok && typeTok->str() == "(")
00946                     typeTok = typeTok->next();
00947 
00948                 if (!type) {
00949                     const Type* t = symbolDatabase->findVariableType(&(*scope), typeTok);
00950                     if (t)
00951                         type = t->classScope;
00952                 }
00953 
00954                 if (type)
00955                     checkMemsetType(&(*scope), tok, type, false);
00956             } else if (tok->variable() && tok->variable()->typeScope() && Token::Match(tok, "%var% = calloc|malloc|realloc|g_malloc|g_try_malloc|g_realloc|g_try_realloc (")) {
00957                 checkMemsetType(&(*scope), tok->tokAt(2), tok->variable()->typeScope(), true);
00958 
00959                 if (tok->variable()->typeScope()->numConstructors > 0 && _settings->isEnabled("warning"))
00960                     mallocOnClassWarning(tok, tok->strAt(2), tok->variable()->typeScope()->classDef);
00961             }
00962         }
00963     }
00964 }
00965 
00966 void CheckClass::checkMemsetType(const Scope *start, const Token *tok, const Scope *type, bool allocation)
00967 {
00968     // recursively check all parent classes
00969     for (std::size_t i = 0; i < type->definedType->derivedFrom.size(); i++) {
00970         if (type->definedType->derivedFrom[i].type && type->definedType->derivedFrom[i].type->classScope)
00971             checkMemsetType(start, tok, type->definedType->derivedFrom[i].type->classScope, allocation);
00972     }
00973 
00974     // Warn if type is a class that contains any virtual functions
00975     std::list<Function>::const_iterator func;
00976 
00977     for (func = type->functionList.begin(); func != type->functionList.end(); ++func) {
00978         if (func->isVirtual) {
00979             if (allocation)
00980                 mallocOnClassError(tok, tok->str(), type->classDef, "virtual method");
00981             else
00982                 memsetError(tok, tok->str(), "virtual method", type->classDef->str());
00983         }
00984     }
00985 
00986     // Warn if type is a class or struct that contains any std::* variables
00987     std::list<Variable>::const_iterator var;
00988 
00989     for (var = type->varlist.begin(); var != type->varlist.end(); ++var) {
00990         // don't warn if variable static or const, pointer or reference
00991         if (!var->isStatic() && !var->isConst() && !var->isPointer() && !var->isReference()) {
00992             const Token *tok1 = var->typeStartToken();
00993 
00994             // check for std:: type
00995             if (Token::simpleMatch(tok1, "std ::"))
00996                 if (allocation)
00997                     mallocOnClassError(tok, tok->str(), type->classDef, "'std::" + tok1->strAt(2) + "'");
00998                 else
00999                     memsetError(tok, tok->str(), "'std::" + tok1->strAt(2) + "'", type->classDef->str());
01000 
01001             // check for known type
01002             else if (var->typeScope())
01003                 checkMemsetType(start, tok, var->typeScope(), allocation);
01004         }
01005     }
01006 }
01007 
01008 void CheckClass::mallocOnClassWarning(const Token* tok, const std::string &memfunc, const Token* classTok)
01009 {
01010     std::list<const Token *> toks;
01011     toks.push_back(tok);
01012     toks.push_back(classTok);
01013     reportError(toks, Severity::warning, "mallocOnClassWarning",
01014                 "Memory for class instance allocated with " + memfunc + "(), but class provides constructors.\n"
01015                 "Memory for class instance allocated with " + memfunc + "(), but class provides constructors. This is unsafe, "
01016                 "since no constructor is called and class members remain uninitialized. Consider using 'new' instead.");
01017 }
01018 
01019 void CheckClass::mallocOnClassError(const Token* tok, const std::string &memfunc, const Token* classTok, const std::string &classname)
01020 {
01021     std::list<const Token *> toks;
01022     toks.push_back(tok);
01023     toks.push_back(classTok);
01024     reportError(toks, Severity::error, "mallocOnClassError",
01025                 "Memory for class instance allocated with " + memfunc + "(), but class contains a " + classname + ".\n"
01026                 "Memory for class instance allocated with " + memfunc + "(), but class a " + classname + ". This is unsafe, "
01027                 "since no constructor is called and class members remain uninitialized. Consider using 'new' instead.");
01028 }
01029 
01030 void CheckClass::memsetError(const Token *tok, const std::string &memfunc, const std::string &classname, const std::string &type)
01031 {
01032     reportError(tok, Severity::error, "memsetClass", "Using '" + memfunc + "' on " + type + " that contains a " + classname + ".");
01033 }
01034 
01035 //---------------------------------------------------------------------------
01036 // ClassCheck: "void operator=(" and "const type & operator=("
01037 //---------------------------------------------------------------------------
01038 
01039 void CheckClass::operatorEq()
01040 {
01041     if (!_settings->isEnabled("style"))
01042         return;
01043 
01044     const std::size_t classes = symbolDatabase->classAndStructScopes.size();
01045     for (std::size_t i = 0; i < classes; ++i) {
01046         const Scope * scope = symbolDatabase->classAndStructScopes[i];
01047         std::list<Function>::const_iterator func;
01048 
01049         for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
01050             if (func->type == Function::eOperatorEqual && func->access != Private) {
01051                 // use definition for check so we don't have to deal with qualification
01052                 if (!(Token::Match(func->tokenDef->tokAt(-3), ";|}|{|public:|protected:|private:|virtual %type% &") &&
01053                       func->tokenDef->strAt(-2) == scope->className)) {
01054                     // make sure we really have a copy assignment operator
01055                     if (Token::Match(func->tokenDef->tokAt(2), "const| %var% &")) {
01056                         if (func->tokenDef->strAt(2) == "const" &&
01057                             func->tokenDef->strAt(3) == scope->className)
01058                             operatorEqReturnError(func->tokenDef->previous(), scope->className);
01059                         else if (func->tokenDef->strAt(2) == scope->className)
01060                             operatorEqReturnError(func->tokenDef->previous(), scope->className);
01061                     }
01062                 }
01063             }
01064         }
01065     }
01066 }
01067 
01068 void CheckClass::operatorEqReturnError(const Token *tok, const std::string &className)
01069 {
01070     reportError(tok, Severity::style, "operatorEq", "'" + className + "::operator=' should return '" + className + " &'.");
01071 }
01072 
01073 //---------------------------------------------------------------------------
01074 // ClassCheck: "C& operator=(const C&) { ... return *this; }"
01075 // operator= should return a reference to *this
01076 //---------------------------------------------------------------------------
01077 
01078 void CheckClass::operatorEqRetRefThis()
01079 {
01080     if (!_settings->isEnabled("style"))
01081         return;
01082 
01083     const std::size_t classes = symbolDatabase->classAndStructScopes.size();
01084     for (std::size_t i = 0; i < classes; ++i) {
01085         const Scope * scope = symbolDatabase->classAndStructScopes[i];
01086         std::list<Function>::const_iterator func;
01087 
01088         for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
01089             if (func->type == Function::eOperatorEqual && func->hasBody) {
01090                 // make sure return signature is correct
01091                 if (Token::Match(func->tokenDef->tokAt(-3), ";|}|{|public:|protected:|private:|virtual %type% &") &&
01092                     func->tokenDef->strAt(-2) == scope->className) {
01093 
01094                     checkReturnPtrThis(&(*scope), &(*func), func->functionScope->classStart, func->functionScope->classEnd);
01095                 }
01096             }
01097         }
01098     }
01099 }
01100 
01101 void CheckClass::checkReturnPtrThis(const Scope *scope, const Function *func, const Token *tok, const Token *last)
01102 {
01103     bool foundReturn = false;
01104 
01105     for (; tok && tok != last; tok = tok->next()) {
01106         // check for return of reference to this
01107         if (tok->str() == "return") {
01108             foundReturn = true;
01109             std::string cast("( " + scope->className + " & )");
01110             if (Token::simpleMatch(tok->next(), cast.c_str()))
01111                 tok = tok->tokAt(4);
01112 
01113             // check if a function is called
01114             if (tok->strAt(2) == "(" &&
01115                 tok->linkAt(2)->next()->str() == ";") {
01116                 std::list<Function>::const_iterator it;
01117 
01118                 // check if it is a member function
01119                 for (it = scope->functionList.begin(); it != scope->functionList.end(); ++it) {
01120                     // check for a regular function with the same name and a body
01121                     if (it->type == Function::eFunction && it->hasBody &&
01122                         it->token->str() == tok->next()->str()) {
01123                         // check for the proper return type
01124                         if (it->tokenDef->previous()->str() == "&" &&
01125                             it->tokenDef->strAt(-2) == scope->className) {
01126                             // make sure it's not a const function
01127                             if (!it->isConst) {
01128                                 /** @todo make sure argument types match */
01129                                 // make sure it's not the same function
01130                                 if (&*it != func)
01131                                     checkReturnPtrThis(scope, &*it, it->arg->link()->next(), it->arg->link()->next()->link());
01132 
01133                                 // just bail for now
01134                                 else
01135                                     return;
01136                             }
01137                         }
01138                     }
01139                 }
01140             }
01141 
01142             // check if *this is returned
01143             else if (!(Token::Match(tok->next(), "(| * this ;|=") ||
01144                        Token::simpleMatch(tok->next(), "operator= (") ||
01145                        Token::simpleMatch(tok->next(), "this . operator= (") ||
01146                        (Token::Match(tok->next(), "%type% :: operator= (") &&
01147                         tok->next()->str() == scope->className)))
01148                 operatorEqRetRefThisError(func->token);
01149         }
01150     }
01151     if (!foundReturn)
01152         operatorEqRetRefThisError(func->token);
01153 }
01154 
01155 void CheckClass::operatorEqRetRefThisError(const Token *tok)
01156 {
01157     reportError(tok, Severity::style, "operatorEqRetRefThis", "'operator=' should return reference to 'this' instance.");
01158 }
01159 
01160 //---------------------------------------------------------------------------
01161 // ClassCheck: "C& operator=(const C& rhs) { if (this == &rhs) ... }"
01162 // operator= should check for assignment to self
01163 //
01164 // For simple classes, an assignment to self check is only a potential optimization.
01165 //
01166 // For classes that allocate dynamic memory, assignment to self can be a real error
01167 // if it is deallocated and allocated again without being checked for.
01168 //
01169 // This check is not valid for classes with multiple inheritance because a
01170 // class can have multiple addresses so there is no trivial way to check for
01171 // assignment to self.
01172 //---------------------------------------------------------------------------
01173 
01174 void CheckClass::operatorEqToSelf()
01175 {
01176     if (!_settings->isEnabled("warning"))
01177         return;
01178 
01179     const std::size_t classes = symbolDatabase->classAndStructScopes.size();
01180     for (std::size_t i = 0; i < classes; ++i) {
01181         const Scope * scope = symbolDatabase->classAndStructScopes[i];
01182         std::list<Function>::const_iterator func;
01183 
01184         // skip classes with multiple inheritance
01185         if (scope->definedType->derivedFrom.size() > 1)
01186             continue;
01187 
01188         for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
01189             if (func->type == Function::eOperatorEqual && func->hasBody) {
01190                 // make sure that the operator takes an object of the same type as *this, otherwise we can't detect self-assignment checks
01191                 if (func->argumentList.empty())
01192                     continue;
01193                 const Token* typeTok = func->argumentList.front().typeEndToken();
01194                 while (typeTok->str() == "const" || typeTok->str() == "&" || typeTok->str() == "*")
01195                     typeTok = typeTok->previous();
01196                 if (typeTok->str() != scope->className)
01197                     continue;
01198 
01199                 // make sure return signature is correct
01200                 if (Token::Match(func->tokenDef->tokAt(-3), ";|}|{|public:|protected:|private: %type% &") &&
01201                     func->tokenDef->strAt(-2) == scope->className) {
01202                     // find the parameter name
01203                     const Token *rhs = func->argumentList.begin()->nameToken();
01204 
01205                     if (!hasAssignSelf(&(*func), rhs)) {
01206                         if (hasAllocation(&(*func), &*scope))
01207                             operatorEqToSelfError(func->token);
01208                     }
01209                 }
01210             }
01211         }
01212     }
01213 }
01214 
01215 bool CheckClass::hasAllocation(const Function *func, const Scope* scope)
01216 {
01217     // This function is called when no simple check was found for assignment
01218     // to self.  We are currently looking for:
01219     //    - deallocate member ; ... member =
01220     //    - alloc member
01221     // That is not ideal because it can cause false negatives but its currently
01222     // necessary to prevent false positives.
01223     const Token *last = func->functionScope->classEnd;
01224     for (const Token *tok = func->functionScope->classStart; tok && (tok != last); tok = tok->next()) {
01225         if (Token::Match(tok, "%var% = malloc|realloc|calloc|new") && isMemberVar(scope, tok))
01226             return true;
01227 
01228         // check for deallocating memory
01229         const Token *var = 0;
01230         if (Token::Match(tok, "free ( %var%"))
01231             var = tok->tokAt(2);
01232         else if (Token::Match(tok, "delete [ ] %var%"))
01233             var = tok->tokAt(3);
01234         else if (Token::Match(tok, "delete %var%"))
01235             var = tok->next();
01236         // Check for assignment to the deleted pointer (only if its a member of the class)
01237         if (var && isMemberVar(scope, var)) {
01238             for (const Token *tok1 = var->next(); tok1 && (tok1 != last); tok1 = tok1->next()) {
01239                 if (Token::Match(tok1, "%var% =")) {
01240                     if (tok1->str() == var->str())
01241                         return true;
01242                 }
01243             }
01244         }
01245     }
01246 
01247     return false;
01248 }
01249 
01250 bool CheckClass::hasAssignSelf(const Function *func, const Token *rhs)
01251 {
01252     const Token *last = func->functionScope->classEnd;
01253     for (const Token *tok = func->functionScope->classStart; tok && tok != last; tok = tok->next()) {
01254         if (Token::simpleMatch(tok, "if (")) {
01255             const Token *tok1 = tok->tokAt(2);
01256             const Token *tok2 = tok->next()->link();
01257 
01258             if (tok1 && tok2) {
01259                 for (; tok1 && tok1 != tok2; tok1 = tok1->next()) {
01260                     if (Token::Match(tok1, "this ==|!= & %var%")) {
01261                         if (tok1->strAt(3) == rhs->str())
01262                             return true;
01263                     } else if (Token::Match(tok1, "& %var% ==|!= this")) {
01264                         if (tok1->strAt(1) == rhs->str())
01265                             return true;
01266                     }
01267                 }
01268             }
01269         }
01270     }
01271 
01272     return false;
01273 }
01274 
01275 void CheckClass::operatorEqToSelfError(const Token *tok)
01276 {
01277     reportError(tok, Severity::warning, "operatorEqToSelf",
01278                 "'operator=' should check for assignment to self to avoid problems with dynamic memory.\n"
01279                 "'operator=' should check for assignment to self to ensure that each block of dynamically "
01280                 "allocated memory is owned and managed by only one instance of the class.");
01281 }
01282 
01283 //---------------------------------------------------------------------------
01284 // A destructor in a base class should be virtual
01285 //---------------------------------------------------------------------------
01286 
01287 void CheckClass::virtualDestructor()
01288 {
01289     // This error should only be given if:
01290     // * base class doesn't have virtual destructor
01291     // * derived class has non-empty destructor
01292     // * base class is deleted
01293 
01294     const std::size_t classes = symbolDatabase->classAndStructScopes.size();
01295     for (std::size_t i = 0; i < classes; ++i) {
01296         const Scope * scope = symbolDatabase->classAndStructScopes[i];
01297 
01298         // Skip base classes
01299         if (scope->definedType->derivedFrom.empty())
01300             continue;
01301 
01302         // Find the destructor
01303         const Function *destructor = scope->getDestructor();
01304 
01305         // Check for destructor with implementation
01306         if (!destructor || !destructor->hasBody)
01307             continue;
01308 
01309         // Empty destructor
01310         if (destructor->token->linkAt(3) == destructor->token->tokAt(4))
01311             continue;
01312 
01313         const Token *derived = scope->classDef;
01314         const Token *derivedClass = derived->next();
01315 
01316         // Iterate through each base class...
01317         for (unsigned int j = 0; j < scope->definedType->derivedFrom.size(); ++j) {
01318             // Check if base class is public and exists in database
01319             if (scope->definedType->derivedFrom[j].access != Private && scope->definedType->derivedFrom[j].type) {
01320                 const Type *derivedFrom = scope->definedType->derivedFrom[j].type;
01321                 const Scope *derivedFromScope = derivedFrom->classScope;
01322                 if (!derivedFromScope)
01323                     continue;
01324 
01325                 // Check for this pattern:
01326                 // 1. Base class pointer is given the address of derived class instance
01327                 // 2. Base class pointer is deleted
01328                 //
01329                 // If this pattern is not seen then bailout the checking of these base/derived classes
01330                 {
01331                     // pointer variables of type 'Base *'
01332                     std::set<unsigned int> basepointer;
01333 
01334                     for (std::size_t k = 0; k < symbolDatabase->getVariableListSize(); k++) {
01335                         const Variable* var = symbolDatabase->getVariableFromVarId(k);
01336                         if (var && var->isPointer() && var->type() == derivedFrom)
01337                             basepointer.insert(var->varId());
01338                     }
01339 
01340                     // pointer variables of type 'Base *' that should not be deleted
01341                     std::set<unsigned int> dontDelete;
01342 
01343                     // No deletion of derived class instance through base class pointer found => the code is ok
01344                     bool ok = true;
01345 
01346                     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
01347                         if (Token::Match(tok, "[;{}] %var% =") &&
01348                             tok->next()->varId() > 0 &&
01349                             basepointer.find(tok->next()->varId()) != basepointer.end()) {
01350                             // new derived class..
01351                             if (Token::simpleMatch(tok->tokAt(3), ("new " + derivedClass->str()).c_str())) {
01352                                 dontDelete.insert(tok->next()->varId());
01353                             }
01354                         }
01355 
01356                         // Delete base class pointer that might point at derived class
01357                         else if (Token::Match(tok, "delete %var% ;") &&
01358                                  tok->next()->varId() &&
01359                                  dontDelete.find(tok->next()->varId()) != dontDelete.end()) {
01360                             ok = false;
01361                             break;
01362                         }
01363                     }
01364 
01365                     // No base class pointer that points at a derived class is deleted
01366                     if (ok)
01367                         continue;
01368                 }
01369 
01370                 // Find the destructor declaration for the base class.
01371                 const Function *base_destructor = derivedFromScope->getDestructor();
01372                 const Token *base = 0;
01373                 if (base_destructor)
01374                     base = base_destructor->token;
01375 
01376                 // Check that there is a destructor..
01377                 if (!base_destructor) {
01378                     if (derivedFrom->derivedFrom.empty())
01379                         virtualDestructorError(derivedFrom->classDef, derivedFrom->name(), derivedClass->str());
01380                 } else if (!base_destructor->isVirtual) {
01381                     // TODO: This is just a temporary fix, better solution is needed.
01382                     // Skip situations where base class has base classes of its own, because
01383                     // some of the base classes might have virtual destructor.
01384                     // Proper solution is to check all of the base classes. If base class is not
01385                     // found or if one of the base classes has virtual destructor, error should not
01386                     // be printed. See TODO test case "virtualDestructorInherited"
01387                     if (derivedFrom->derivedFrom.empty()) {
01388                         // Make sure that the destructor is public (protected or private
01389                         // would not compile if inheritance is used in a way that would
01390                         // cause the bug we are trying to find here.)
01391                         if (base_destructor->access == Public)
01392                             virtualDestructorError(base, derivedFrom->name(), derivedClass->str());
01393                     }
01394                 }
01395             }
01396         }
01397     }
01398 }
01399 
01400 void CheckClass::virtualDestructorError(const Token *tok, const std::string &Base, const std::string &Derived)
01401 {
01402     reportError(tok, Severity::error, "virtualDestructor", "Class '" + Base + "' which is inherited by class '" + Derived + "' does not have a virtual destructor.\n"
01403                 "Class '" + Base + "' which is inherited by class '" + Derived + "' does not have a virtual destructor. "
01404                 "If you destroy instances of the derived class by deleting a pointer that points to the base class, only "
01405                 "the destructor of the base class is executed. Thus, dynamic memory that is managed by the derived class "
01406                 "could leak. This can be avoided by adding a virtual destructor to the base class.");
01407 }
01408 
01409 //---------------------------------------------------------------------------
01410 // warn for "this-x". The indented code may be "this->x"
01411 //---------------------------------------------------------------------------
01412 
01413 void CheckClass::thisSubtraction()
01414 {
01415     if (!_settings->isEnabled("warning"))
01416         return;
01417 
01418     const Token *tok = _tokenizer->tokens();
01419     for (;;) {
01420         tok = Token::findmatch(tok, "this - %var%");
01421         if (!tok)
01422             break;
01423 
01424         if (tok->strAt(-1) != "*")
01425             thisSubtractionError(tok);
01426 
01427         tok = tok->next();
01428     }
01429 }
01430 
01431 void CheckClass::thisSubtractionError(const Token *tok)
01432 {
01433     reportError(tok, Severity::warning, "thisSubtraction", "Suspicious pointer subtraction. Did you intend to write '->'?");
01434 }
01435 
01436 //---------------------------------------------------------------------------
01437 // can member function be const?
01438 //---------------------------------------------------------------------------
01439 
01440 void CheckClass::checkConst()
01441 {
01442     // This is an inconclusive check. False positives: #3322.
01443     if (!_settings->inconclusive)
01444         return;
01445 
01446     if (!_settings->isEnabled("style"))
01447         return;
01448 
01449     const std::size_t classes = symbolDatabase->classAndStructScopes.size();
01450     for (std::size_t i = 0; i < classes; ++i) {
01451         const Scope * scope = symbolDatabase->classAndStructScopes[i];
01452         std::list<Function>::const_iterator func;
01453 
01454         for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
01455             // does the function have a body?
01456             if (func->type == Function::eFunction && func->hasBody && !func->isFriend && !func->isStatic && !func->isVirtual) {
01457                 // get last token of return type
01458                 const Token *previous = func->tokenDef->previous();
01459 
01460                 // does the function return a pointer or reference?
01461                 if (Token::Match(previous, "*|&")) {
01462                     const Token *temp = previous;
01463 
01464                     while (!Token::Match(temp->previous(), ";|}|{|public:|protected:|private:"))
01465                         temp = temp->previous();
01466 
01467                     if (temp->str() != "const")
01468                         continue;
01469                 } else if (Token::Match(previous->previous(), "*|& >")) {
01470                     const Token *temp = previous;
01471 
01472                     while (!Token::Match(temp->previous(), ";|}|{|public:|protected:|private:")) {
01473                         temp = temp->previous();
01474                         if (temp->str() == "const")
01475                             break;
01476                     }
01477 
01478                     if (temp->str() != "const")
01479                         continue;
01480                 } else if (func->isOperator && Token::Match(previous, ";|{|}|public:|private:|protected:")) { // Operator without return type: conversion operator
01481                     const std::string& opName = func->tokenDef->str();
01482                     if (opName.compare(8, 5, "const") != 0 && opName[opName.size()-1] == '&')
01483                         continue;
01484                 } else {
01485                     // don't warn for unknown types..
01486                     // LPVOID, HDC, etc
01487                     if (previous->isUpperCaseName() && previous->str().size() > 2 && !symbolDatabase->isClassOrStruct(previous->str()))
01488                         continue;
01489                 }
01490 
01491                 // check if base class function is virtual
01492                 if (!scope->definedType->derivedFrom.empty()) {
01493                     if (func->isImplicitlyVirtual(true))
01494                         continue;
01495                 }
01496 
01497                 bool memberAccessed = false;
01498                 // if nothing non-const was found. write error..
01499                 if (checkConstFunc(&(*scope), &*func, memberAccessed)) {
01500                     std::string classname = scope->className;
01501                     const Scope *nest = scope->nestedIn;
01502                     while (nest && nest->type != Scope::eGlobal) {
01503                         classname = std::string(nest->className + "::" + classname);
01504                         nest = nest->nestedIn;
01505                     }
01506 
01507                     // get function name
01508                     std::string functionName = (func->tokenDef->isName() ? "" : "operator") + func->tokenDef->str();
01509 
01510                     if (func->tokenDef->str() == "(")
01511                         functionName += ")";
01512                     else if (func->tokenDef->str() == "[")
01513                         functionName += "]";
01514 
01515                     if (!func->isConst || (!memberAccessed && !func->isOperator)) {
01516                         if (func->isInline)
01517                             checkConstError(func->token, classname, functionName, !memberAccessed && !func->isOperator);
01518                         else // not inline
01519                             checkConstError2(func->token, func->tokenDef, classname, functionName, !memberAccessed && !func->isOperator);
01520                     }
01521                 }
01522             }
01523         }
01524     }
01525 }
01526 
01527 bool CheckClass::isMemberVar(const Scope *scope, const Token *tok)
01528 {
01529     bool again = false;
01530 
01531     // try to find the member variable
01532     do {
01533         again = false;
01534 
01535         if (tok->str() == "this") {
01536             return true;
01537         } else if (Token::simpleMatch(tok->tokAt(-3), "( * this )")) {
01538             return true;
01539         } else if (Token::Match(tok->tokAt(-2), "%var% . %var%")) {
01540             tok = tok->tokAt(-2);
01541             again = true;
01542         } else if (Token::Match(tok->tokAt(-2), "] . %var%")) {
01543             tok = tok->linkAt(-2)->previous();
01544             again = true;
01545         } else if (tok->str() == "]") {
01546             tok = tok->link()->previous();
01547             again = true;
01548         }
01549     } while (again);
01550 
01551     std::list<Variable>::const_iterator var;
01552     for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) {
01553         if (var->name() == tok->str()) {
01554             if (tok->varId() == 0)
01555                 symbolDatabase->debugMessage(tok, "CheckClass::isMemberVar found used member variable \'" + tok->str() + "\' with varid 0");
01556 
01557             return !var->isStatic();
01558         }
01559     }
01560 
01561     // not found in this class
01562     if (!scope->definedType->derivedFrom.empty()) {
01563         // check each base class
01564         for (unsigned int i = 0; i < scope->definedType->derivedFrom.size(); ++i) {
01565             // find the base class
01566             const Type *derivedFrom = scope->definedType->derivedFrom[i].type;
01567 
01568             // find the function in the base class
01569             if (derivedFrom && derivedFrom->classScope) {
01570                 if (isMemberVar(derivedFrom->classScope, tok))
01571                     return true;
01572             }
01573         }
01574     }
01575 
01576     return false;
01577 }
01578 
01579 static unsigned int countParameters(const Token *tok)
01580 {
01581     tok = tok->tokAt(2);
01582     if (tok->str() == ")")
01583         return 0;
01584 
01585     unsigned int numpar = 1;
01586     while (NULL != (tok = tok->nextArgument()))
01587         numpar++;
01588 
01589     return numpar;
01590 }
01591 
01592 static unsigned int countMinArgs(const Token* argList)
01593 {
01594     if (!argList)
01595         return 0;
01596 
01597     argList = argList->next();
01598     if (argList->str() == ")")
01599         return 0;
01600 
01601     unsigned int count = 1;
01602     for (; argList; argList = argList->next()) {
01603         if (argList->link() && Token::Match(argList, "(|[|{|<"))
01604             argList = argList->link();
01605         else if (argList->str() == ",")
01606             count++;
01607         else if (argList->str() == "=")
01608             return count-1;
01609         else if (argList->str() == ")")
01610             break;
01611     }
01612     return count;
01613 }
01614 
01615 bool CheckClass::isMemberFunc(const Scope *scope, const Token *tok)
01616 {
01617     unsigned int args = countParameters(tok);
01618 
01619     for (std::list<Function>::const_iterator func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
01620         /** @todo we need to look at the argument types when there are overloaded functions
01621           * with the same number of arguments */
01622         if (func->tokenDef->str() == tok->str() && (func->argCount() == args || (func->argCount() > args && countMinArgs(func->argDef) <= args))) {
01623             return !func->isStatic;
01624         }
01625     }
01626 
01627     // not found in this class
01628     if (!scope->definedType->derivedFrom.empty()) {
01629         // check each base class
01630         for (unsigned int i = 0; i < scope->definedType->derivedFrom.size(); ++i) {
01631             // find the base class
01632             const Type *derivedFrom = scope->definedType->derivedFrom[i].type;
01633 
01634             // find the function in the base class
01635             if (derivedFrom && derivedFrom->classScope) {
01636                 if (isMemberFunc(derivedFrom->classScope, tok))
01637                     return true;
01638             }
01639         }
01640     }
01641 
01642     return false;
01643 }
01644 
01645 bool CheckClass::isConstMemberFunc(const Scope *scope, const Token *tok)
01646 {
01647     unsigned int args = countParameters(tok);
01648 
01649     std::list<Function>::const_iterator func;
01650     unsigned int matches = 0;
01651     unsigned int consts = 0;
01652 
01653     for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
01654         /** @todo we need to look at the argument types when there are overloaded functions
01655           * with the same number of arguments */
01656         if (func->tokenDef->str() == tok->str() && (func->argCount() == args || (func->argCount() > args && countMinArgs(func->argDef) <= args))) {
01657             matches++;
01658             if (func->isConst)
01659                 consts++;
01660         }
01661     }
01662 
01663     // if there are multiple matches that are all const, return const
01664     if (matches > 0 && matches == consts)
01665         return true;
01666 
01667     // not found in this class
01668     if (!scope->definedType->derivedFrom.empty()) {
01669         // check each base class
01670         for (unsigned int i = 0; i < scope->definedType->derivedFrom.size(); ++i) {
01671             // find the base class
01672             const Type *derivedFrom = scope->definedType->derivedFrom[i].type;
01673 
01674             // find the function in the base class
01675             if (derivedFrom && derivedFrom->classScope) {
01676                 if (isConstMemberFunc(derivedFrom->classScope, tok))
01677                     return true;
01678             }
01679         }
01680     }
01681 
01682     return false;
01683 }
01684 
01685 bool CheckClass::checkConstFunc(const Scope *scope, const Function *func, bool& memberAccessed)
01686 {
01687     // if the function doesn't have any assignment nor function call,
01688     // it can be a const function..
01689     for (const Token *tok1 = func->functionScope->classStart; tok1 && tok1 != func->functionScope->classEnd; tok1 = tok1->next()) {
01690         if (tok1->isName() && isMemberVar(scope, tok1)) {
01691             memberAccessed = true;
01692             const Variable* v = tok1->variable();
01693             if (v && v->isMutable())
01694                 continue;
01695 
01696             if (tok1->str() == "this" && tok1->previous()->isAssignmentOp())
01697                 return(false);
01698 
01699             const Token* jumpBackToken = 0;
01700             const Token *lastVarTok = tok1;
01701             const Token *end = tok1;
01702             for (;;) {
01703                 if (Token::Match(end->next(), ". %var%")) {
01704                     end = end->tokAt(2);
01705                     if (end->varId())
01706                         lastVarTok = end;
01707                 } else if (end->strAt(1) == "[") {
01708                     if (end->varId()) {
01709                         const Variable *var = end->variable();
01710 
01711                         if (var && Token::simpleMatch(var->typeStartToken(), "std :: map")) // operator[] changes a map
01712                             return(false);
01713                     }
01714                     if (!jumpBackToken)
01715                         jumpBackToken = end->next(); // Check inside the [] brackets
01716                     end = end->linkAt(1);
01717                 } else if (end->strAt(1) == ")")
01718                     end = end->next();
01719                 else
01720                     break;
01721             }
01722 
01723             if (end->strAt(1) == "(") {
01724                 const Variable *var = lastVarTok->variable();
01725                 if (!var)
01726                     return(false);
01727                 if (Token::simpleMatch(var->typeStartToken(), "std ::") // assume all std::*::size() and std::*::empty() are const
01728                     && (Token::Match(end, "size|empty|cend|crend|cbegin|crbegin|max_size|length|count|capacity|get_allocator|c_str|str ( )") || Token::Match(end, "rfind|copy")))
01729                     ;
01730                 else if (!var->typeScope() || !isConstMemberFunc(var->typeScope(), end))
01731                     return(false);
01732             }
01733 
01734             // Assignment
01735             else if (end->next()->type() == Token::eAssignmentOp)
01736                 return(false);
01737 
01738             // Streaming
01739             else if (end->strAt(1) == "<<" && tok1->strAt(-1) != "<<")
01740                 return(false);
01741             else if (tok1->strAt(-1) == ">>")
01742                 return(false);
01743 
01744             // ++/--
01745             else if (end->next()->type() == Token::eIncDecOp || tok1->previous()->type() == Token::eIncDecOp)
01746                 return(false);
01747 
01748 
01749             const Token* start = tok1;
01750             while (tok1->strAt(-1) == ")")
01751                 tok1 = tok1->linkAt(-1);
01752 
01753             if (start->strAt(-1) == "delete")
01754                 return(false);
01755 
01756             tok1 = jumpBackToken?jumpBackToken:end; // Jump back to first [ to check inside, or jump to end of expression
01757         }
01758 
01759         // streaming: <<
01760         else if (Token::simpleMatch(tok1->previous(), ") <<") &&
01761                  isMemberVar(scope, tok1->tokAt(-2))) {
01762             const Variable* var = tok1->tokAt(-2)->variable();
01763             if (!var || !var->isMutable())
01764                 return(false);
01765         }
01766 
01767 
01768         // function call..
01769         else if (Token::Match(tok1, "%var% (") && !tok1->isStandardType() &&
01770                  !Token::Match(tok1, "return|if|string|switch|while|catch|for")) {
01771             if (isMemberFunc(scope, tok1) && tok1->strAt(-1) != ".") {
01772                 if (!isConstMemberFunc(scope, tok1))
01773                     return(false);
01774                 memberAccessed = true;
01775             }
01776             // Member variable given as parameter
01777             for (const Token* tok2 = tok1->tokAt(2); tok2 && tok2 != tok1->next()->link(); tok2 = tok2->next()) {
01778                 if (tok2->str() == "(")
01779                     tok2 = tok2->link();
01780                 else if (tok2->isName() && isMemberVar(scope, tok2)) {
01781                     const Variable* var = tok2->variable();
01782                     if (!var || !var->isMutable())
01783                         return(false); // TODO: Only bailout if function takes argument as non-const reference
01784                 }
01785             }
01786         } else if (Token::simpleMatch(tok1, "> (") && (!tok1->link() || !Token::Match(tok1->link()->previous(), "static_cast|const_cast|dynamic_cast|reinterpret_cast"))) {
01787             return(false);
01788         }
01789     }
01790 
01791     return(true);
01792 }
01793 
01794 void CheckClass::checkConstError(const Token *tok, const std::string &classname, const std::string &funcname, bool suggestStatic)
01795 {
01796     checkConstError2(tok, 0, classname, funcname, suggestStatic);
01797 }
01798 
01799 void CheckClass::checkConstError2(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &funcname, bool suggestStatic)
01800 {
01801     std::list<const Token *> toks;
01802     toks.push_back(tok1);
01803     if (tok2)
01804         toks.push_back(tok2);
01805     if (!suggestStatic)
01806         reportError(toks, Severity::style, "functionConst",
01807                     "Technically the member function '" + classname + "::" + funcname + "' can be const.\n"
01808                     "The member function '" + classname + "::" + funcname + "' can be made a const "
01809                     "function. Making this function 'const' should not cause compiler errors. "
01810                     "Even though the function can be made const function technically it may not make "
01811                     "sense conceptually. Think about your design and the task of the function first - is "
01812                     "it a function that must not change object internal state?", true);
01813     else
01814         reportError(toks, Severity::performance, "functionStatic",
01815                     "Technically the member function '" + classname + "::" + funcname + "' can be static.\n"
01816                     "The member function '" + classname + "::" + funcname + "' can be made a static "
01817                     "function. Making a function static can bring a performance benefit since no 'this' instance is "
01818                     "passed to the function. This change should not cause compiler errors but it does not "
01819                     "necessarily make sense conceptually. Think about your design and the task of the function first - "
01820                     "is it a function that must not access members of class instances?", true);
01821 }
01822 
01823 //---------------------------------------------------------------------------
01824 // ClassCheck: Check that initializer list is in declared order.
01825 //---------------------------------------------------------------------------
01826 
01827 struct VarInfo {
01828     VarInfo(const Variable *_var, const Token *_tok)
01829         : var(_var), tok(_tok) { }
01830 
01831     const Variable *var;
01832     const Token *tok;
01833 };
01834 
01835 void CheckClass::initializerListOrder()
01836 {
01837     if (!_settings->isEnabled("style"))
01838         return;
01839 
01840     // This check is not inconclusive.  However it only determines if the initialization
01841     // order is incorrect.  It does not determine if being out of order causes
01842     // a real error.  Out of order is not necessarily an error but you can never
01843     // have an error if the list is in order so this enforces defensive programming.
01844     if (!_settings->inconclusive)
01845         return;
01846 
01847     const std::size_t classes = symbolDatabase->classAndStructScopes.size();
01848     for (std::size_t i = 0; i < classes; ++i) {
01849         const Scope * info = symbolDatabase->classAndStructScopes[i];
01850         std::list<Function>::const_iterator func;
01851 
01852         // iterate through all member functions looking for constructors
01853         for (func = info->functionList.begin(); func != info->functionList.end(); ++func) {
01854             if ((func->isConstructor()) && func->hasBody) {
01855                 // check for initializer list
01856                 const Token *tok = func->arg->link()->next();
01857 
01858                 if (tok->str() == ":") {
01859                     std::vector<VarInfo> vars;
01860                     tok = tok->next();
01861 
01862                     // find all variable initializations in list
01863                     while (tok && tok->str() != "{") {
01864                         if (Token::Match(tok, "%var% (")) {
01865                             const Variable *var = info->getVariable(tok->str());
01866 
01867                             if (var)
01868                                 vars.push_back(VarInfo(var, tok));
01869 
01870                             if (Token::Match(tok->tokAt(2), "%var% =")) {
01871                                 var = info->getVariable(tok->strAt(2));
01872 
01873                                 if (var)
01874                                     vars.push_back(VarInfo(var, tok->tokAt(2)));
01875                             }
01876                             tok = tok->next()->link()->next();
01877                         } else
01878                             tok = tok->next();
01879                     }
01880 
01881                     // need at least 2 members to have out of order initialization
01882                     for (std::size_t j = 1; j < vars.size(); j++) {
01883                         // check for out of order initialization
01884                         if (vars[j].var->index() < vars[j - 1].var->index())
01885                             initializerListError(vars[j].tok,vars[j].var->nameToken(), info->className, vars[j].var->name());
01886                     }
01887                 }
01888             }
01889         }
01890     }
01891 }
01892 
01893 void CheckClass::initializerListError(const Token *tok1, const Token *tok2, const std::string &classname, const std::string &varname)
01894 {
01895     std::list<const Token *> toks;
01896     toks.push_back(tok1);
01897     toks.push_back(tok2);
01898     reportError(toks, Severity::style, "initializerList",
01899                 "Member variable '" + classname + "::" +
01900                 varname + "' is in the wrong place in the initializer list.\n"
01901                 "Member variable '" + classname + "::" +
01902                 varname + "' is in the wrong place in the initializer list. "
01903                 "Members are initialized in the order they are declared, not in the "
01904                 "order they are in the initializer list.  Keeping the initializer list "
01905                 "in the same order that the members were declared prevents order dependent "
01906                 "initialization errors.", true);
01907 }
01908 
01909 void CheckClass::checkPureVirtualFunctionCall()
01910 {
01911     const std::size_t functions = symbolDatabase->functionScopes.size();
01912     std::map<const Function *, std::list<const Token *> > callsPureVirtualFunctionMap;
01913     for (std::size_t i = 0; i < functions; ++i) {
01914         const Scope * scope = symbolDatabase->functionScopes[i];
01915         if (scope->function == 0 || !scope->function->hasBody ||
01916             !(scope->function->isConstructor() ||
01917               scope->function->isDestructor()))
01918             continue;
01919 
01920         const std::list<const Token *> & pureVirtualFunctionCalls=callsPureVirtualFunction(*scope->function,callsPureVirtualFunctionMap);
01921         for (std::list<const Token *>::const_iterator pureCallIter=pureVirtualFunctionCalls.begin();
01922              pureCallIter!=pureVirtualFunctionCalls.end();
01923              ++pureCallIter) {
01924             const Token & pureCall=**pureCallIter;
01925             std::list<const Token *> pureFuncStack;
01926             pureFuncStack.push_back(&pureCall);
01927             getFirstPureVirtualFunctionCallStack(callsPureVirtualFunctionMap, pureCall, pureFuncStack);
01928             if (!pureFuncStack.empty())
01929                 callsPureVirtualFunctionError(*scope->function, pureFuncStack, pureFuncStack.back()->str());
01930         }
01931     }
01932 }
01933 
01934 const std::list<const Token *> & CheckClass::callsPureVirtualFunction(const Function & function,
01935         std::map<const Function *, std::list<const Token *> > & callsPureVirtualFunctionMap)
01936 {
01937     std::pair<std::map<const Function *, std::list<const Token *> >::iterator , bool > found=
01938         callsPureVirtualFunctionMap.insert(std::pair<const Function *, std::list< const Token *> >(&function,std::list<const Token *>()));
01939     std::list<const Token *> & pureFunctionCalls=found.first->second;
01940     if (found.second) {
01941         if (function.hasBody) {
01942             for (const Token *tok = function.arg->link();
01943                  tok != function.functionScope->classEnd;
01944                  tok = tok->next()) {
01945                 const Function * callFunction=tok->function();
01946                 if (!callFunction ||
01947                     function.nestedIn != callFunction->nestedIn ||
01948                     (tok->previous() && tok->previous()->str()=="."))
01949                     continue;
01950 
01951                 if (isPureWithoutBody(*callFunction)) {
01952                     pureFunctionCalls.push_back(tok);
01953                     continue;
01954                 }
01955 
01956                 const std::list<const Token *> & pureFunctionCallsOfTok=callsPureVirtualFunction(*callFunction,
01957                         callsPureVirtualFunctionMap);
01958                 if (!pureFunctionCallsOfTok.empty()) {
01959                     pureFunctionCalls.push_back(tok);
01960                     continue;
01961                 }
01962             }
01963         }
01964     }
01965     return pureFunctionCalls;
01966 }
01967 
01968 void CheckClass::getFirstPureVirtualFunctionCallStack(
01969     std::map<const Function *, std::list<const Token *> > & callsPureVirtualFunctionMap,
01970     const Token & pureCall,
01971     std::list<const Token *> & pureFuncStack)
01972 {
01973     if (isPureWithoutBody(*pureCall.function())) {
01974         pureFuncStack.push_back(pureCall.function()->token);
01975         return;
01976     }
01977     std::map<const Function *, std::list<const Token *> >::const_iterator found=callsPureVirtualFunctionMap.find(pureCall.function());
01978     if (found==callsPureVirtualFunctionMap.end() ||
01979         found->second.empty()) {
01980         pureFuncStack.clear();
01981         return;
01982     }
01983     const Token & firstPureCall=**found->second.begin();
01984     pureFuncStack.push_back(&firstPureCall);
01985     getFirstPureVirtualFunctionCallStack(callsPureVirtualFunctionMap, firstPureCall, pureFuncStack);
01986 }
01987 
01988 void CheckClass::callsPureVirtualFunctionError(
01989     const Function & scopeFunction,
01990     const std::list<const Token *> & tokStack,
01991     const std::string &purefuncname)
01992 {
01993     const char * scopeFunctionTypeName=getFunctionTypeName(scopeFunction.type);
01994     reportError(tokStack, Severity::warning, "pureVirtualCall", "Call of pure virtual function '" + purefuncname + "' in " + scopeFunctionTypeName + ".\n"
01995                 "Call of pure virtual function '" + purefuncname + "' in " + scopeFunctionTypeName + ". The call will fail during runtime.");
01996 }
01997