diff --git a/Makefile b/Makefile index d286ab7ef..1644d1617 100644 --- a/Makefile +++ b/Makefile @@ -44,6 +44,7 @@ LIBOBJ = lib/checkautovariables.o \ lib/path.o \ lib/preprocessor.o \ lib/settings.o \ + lib/symboldatabase.o \ lib/timer.o \ lib/token.o \ lib/tokenize.o @@ -135,7 +136,7 @@ lib/checkautovariables.o: lib/checkautovariables.cpp lib/checkautovariables.h li lib/checkbufferoverrun.o: lib/checkbufferoverrun.cpp lib/checkbufferoverrun.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h lib/mathlib.h lib/executionpath.h $(CXX) $(CXXFLAGS) -Ilib -c -o lib/checkbufferoverrun.o lib/checkbufferoverrun.cpp -lib/checkclass.o: lib/checkclass.cpp lib/checkclass.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h +lib/checkclass.o: lib/checkclass.cpp lib/checkclass.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h $(CXX) $(CXXFLAGS) -Ilib -c -o lib/checkclass.o lib/checkclass.cpp lib/checkexceptionsafety.o: lib/checkexceptionsafety.cpp lib/checkexceptionsafety.h lib/check.h lib/token.h lib/tokenize.h lib/settings.h lib/errorlogger.h @@ -195,6 +196,9 @@ lib/preprocessor.o: lib/preprocessor.cpp lib/preprocessor.h lib/tokenize.h lib/t lib/settings.o: lib/settings.cpp lib/settings.h $(CXX) $(CXXFLAGS) -Ilib -c -o lib/settings.o lib/settings.cpp +lib/symboldatabase.o: lib/symboldatabase.cpp lib/symboldatabase.h lib/tokenize.h lib/token.h lib/settings.h lib/errorlogger.h lib/check.h + $(CXX) $(CXXFLAGS) -Ilib -c -o lib/symboldatabase.o lib/symboldatabase.cpp + lib/timer.o: lib/timer.cpp lib/timer.h $(CXX) $(CXXFLAGS) -Ilib -c -o lib/timer.o lib/timer.cpp @@ -228,13 +232,13 @@ test/testbufferoverrun.o: test/testbufferoverrun.cpp lib/tokenize.h lib/checkbuf test/testcharvar.o: test/testcharvar.cpp lib/tokenize.h lib/checkother.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h test/testsuite.h test/redirect.h $(CXX) $(CXXFLAGS) -Ilib -Icli -c -o test/testcharvar.o test/testcharvar.cpp -test/testclass.o: test/testclass.cpp lib/tokenize.h lib/checkclass.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h test/testsuite.h test/redirect.h +test/testclass.o: test/testclass.cpp lib/tokenize.h lib/checkclass.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h test/testsuite.h test/redirect.h $(CXX) $(CXXFLAGS) -Ilib -Icli -c -o test/testclass.o test/testclass.cpp test/testcmdlineparser.o: test/testcmdlineparser.cpp test/testsuite.h lib/errorlogger.h test/redirect.h lib/settings.h $(CXX) $(CXXFLAGS) -Ilib -Icli -c -o test/testcmdlineparser.o test/testcmdlineparser.cpp -test/testconstructors.o: test/testconstructors.cpp lib/tokenize.h lib/checkclass.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h test/testsuite.h test/redirect.h +test/testconstructors.o: test/testconstructors.cpp lib/tokenize.h lib/checkclass.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h test/testsuite.h test/redirect.h $(CXX) $(CXXFLAGS) -Ilib -Icli -c -o test/testconstructors.o test/testconstructors.cpp test/testcppcheck.o: test/testcppcheck.cpp lib/cppcheck.h lib/settings.h lib/errorlogger.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/tokenize.h test/testsuite.h test/redirect.h lib/path.h test/tinyxml/tinyxml.h test/tinyxml/tinystr.h @@ -306,7 +310,7 @@ test/testuninitvar.o: test/testuninitvar.cpp lib/tokenize.h lib/checkuninitvar.h test/testunusedfunctions.o: test/testunusedfunctions.cpp lib/tokenize.h test/testsuite.h lib/errorlogger.h test/redirect.h lib/checkunusedfunctions.h lib/check.h lib/token.h lib/settings.h $(CXX) $(CXXFLAGS) -Ilib -Icli -c -o test/testunusedfunctions.o test/testunusedfunctions.cpp -test/testunusedprivfunc.o: test/testunusedprivfunc.cpp lib/tokenize.h lib/checkclass.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h test/testsuite.h test/redirect.h +test/testunusedprivfunc.o: test/testunusedprivfunc.cpp lib/tokenize.h lib/checkclass.h lib/check.h lib/token.h lib/settings.h lib/errorlogger.h lib/symboldatabase.h test/testsuite.h test/redirect.h $(CXX) $(CXXFLAGS) -Ilib -Icli -c -o test/testunusedprivfunc.o test/testunusedprivfunc.cpp test/testunusedvar.o: test/testunusedvar.cpp test/testsuite.h lib/errorlogger.h test/redirect.h lib/tokenize.h lib/checkother.h lib/check.h lib/token.h lib/settings.h diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 1d960fe82..818ed0f0d 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -22,6 +22,7 @@ #include "tokenize.h" #include "token.h" #include "errorlogger.h" +#include "symboldatabase.h" #include @@ -42,1232 +43,23 @@ CheckClass instance; CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) : Check(tokenizer, settings, errorLogger), - hasSymbolDatabase(false) + symbolDatabase(NULL) { } -static bool isFunction(const Token *tok, const Token **funcStart, const Token **argStart) +CheckClass::~CheckClass() { - // function returning function pointer? '... ( ... %var% ( ... ))( ... ) {' - if (tok->str() == "(" && - tok->link()->previous()->str() == ")" && - tok->link()->next() && - tok->link()->next()->str() == "(" && - tok->link()->next()->link()->next() && - Token::Match(tok->link()->next()->link()->next(), "{|;|const|=")) - { - *funcStart = tok->link()->previous()->link()->previous(); - *argStart = tok->link()->previous()->link(); - return true; - } - - // regular function? - else if (Token::Match(tok, "%var% (") && Token::Match(tok->next()->link(), ") const| ;|{|=|:")) - { - *funcStart = tok; - *argStart = tok->next(); - return true; - } - - // simple operator? - else if (Token::Match(tok, "operator %any% (") && Token::Match(tok->tokAt(2)->link(), ") const| ;|{|=|:")) - { - *funcStart = tok->next(); - *argStart = tok->tokAt(2); - return true; - } - - // complex operator? - else if (tok->str() == "operator") - { - // operator[] or operator()? - if ((Token::simpleMatch(tok->next(), "( ) (") || Token::simpleMatch(tok->next(), "[ ] (")) && - Token::Match(tok->tokAt(3)->link(), ") const| ;|{|=|:")) - { - *funcStart = tok->next(); - *argStart = tok->tokAt(3); - return true; - } - - // operator new/delete []? - else if (Token::Match(tok->next(), "new|delete [ ] (") && Token::Match(tok->tokAt(4)->link(), ") ;|{")) - { - *funcStart = tok->next(); - *argStart = tok->tokAt(4); - return true; - } - } - - return false; -} - -void CheckClass::addFunction(SpaceInfo **info, const Token **tok, const Token *argStart) -{ - const Token *tok1 = (*tok)->tokAt(-2); - int count = 0; - bool added = false; - std::string path; - unsigned int path_length = 0; - - // back up to head of path - while (tok1->previous() && tok1->previous()->str() == "::") - { - path = tok1->str() + " :: " + path; - tok1 = tok1->tokAt(-2); - count++; - path_length++; - } - - if (count) - { - path = tok1->str() + " :: " + path; - path_length++; - } - - std::list::iterator it1; - - // search for match - for (it1 = spaceInfoList.begin(); it1 != spaceInfoList.end(); ++it1) - { - SpaceInfo *info1 = *it1; - - // is this class at global scope? - if (*info) - { - if (!info1->nestedIn) - continue; - } - else - { - if (info1->nestedIn) - continue; - } - - bool match = false; - if (info1->className == tok1->str() && - ((*info) ? (info1->nestedIn->className == (*info)->className) : true)) - { - SpaceInfo *info2 = info1; - - while (info2 && count > 0) - { - count--; - tok1 = tok1->tokAt(2); - info2 = info2->findInNestedList(tok1->str()); - } - - if (count == 0 && info2) - { - match = true; - info1 = info2; - } - } - - if (match) - { - std::list::iterator func; - - for (func = info1->functionList.begin(); func != info1->functionList.end(); ++func) - { - if (!func->hasBody) - { - if (func->isOperator && - (*tok)->str() == "operator" && - func->tokenDef->str() == (*tok)->strAt(1)) - { - if (argsMatch(func->tokenDef->tokAt(2), (*tok)->tokAt(3), path, path_length)) - { - func->hasBody = true; - func->token = (*tok)->next(); - func->arg = argStart; - } - } - else if (func->tokenDef->str() == (*tok)->str()) - { - if (argsMatch(func->tokenDef->next(), (*tok)->next(), path, path_length)) - { - // normal function? - if (!func->retFuncPtr && (*tok)->next()->link()) - { - if ((func->isConst && (*tok)->next()->link()->next()->str() == "const") || - (!func->isConst && (*tok)->next()->link()->next()->str() != "const")) - { - func->hasBody = true; - func->token = (*tok); - func->arg = argStart; - } - } - - // function returning function pointer? - else if (func->retFuncPtr) - { - // todo check for const - func->hasBody = true; - func->token = (*tok); - func->arg = argStart; - } - } - } - - if (func->hasBody) - { - addNewFunction(info, tok); - added = true; - break; - } - } - } - } - } - - // check for class function for unknown class - if (!added) - addNewFunction(info, tok); -} - -void CheckClass::addNewFunction(SpaceInfo **info, const Token **tok) -{ - const Token *tok1 = *tok; - SpaceInfo *new_info = new SpaceInfo(this, tok1, *info); - - // skip to start of function - while (tok1 && tok1->str() != "{") - tok1 = tok1->next(); - - if (tok1) - { - new_info->classStart = tok1; - new_info->classEnd = tok1->link(); - - *info = new_info; - - // add space - spaceInfoList.push_back(new_info); - - *tok = tok1; - } -} - -void CheckClass::addIfFunction(SpaceInfo **info, const Token **tok) -{ - const Token *funcStart = 0; - const Token *argStart = 0; - - // function? - if (isFunction(*tok, &funcStart, &argStart)) - { - // has body? - if (Token::Match(argStart->link(), ") const| {|:")) - { - // class function - if ((*tok)->previous() && (*tok)->previous()->str() == "::") - addFunction(info, tok, argStart); - - // regular function - else - addNewFunction(info, tok); - } - - // function returning function pointer with body - else if (Token::simpleMatch(argStart->link(), ") ) (") && - Token::Match(argStart->link()->tokAt(2)->link(), ") const| {")) - { - const Token *tok1 = funcStart; - - // class function - if (tok1->previous()->str() == "::") - addFunction(info, &tok1, argStart); - - // regular function - else - addNewFunction(info, &tok1); - - *tok = tok1; - } - } + delete symbolDatabase; } void CheckClass::createSymbolDatabase() { // Multiple calls => bail out - if (hasSymbolDatabase) + if (symbolDatabase) return; - hasSymbolDatabase = true; - - // find all namespaces (class,struct and namespace) - SpaceInfo *info = 0; - for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) - { - // Locate next class - if (Token::Match(tok, "class|struct|namespace %var% [{:]")) - { - SpaceInfo *new_info = new SpaceInfo(this, tok, info); - const Token *tok2 = tok->tokAt(2); - - // only create base list for classes and structures - if (new_info->type == SpaceInfo::Class || new_info->type == SpaceInfo::Struct) - { - // goto initial '{' - tok2 = initBaseInfo(new_info, tok); - } - - new_info->classStart = tok2; - new_info->classEnd = tok2->link(); - - info = new_info; - - // add namespace - spaceInfoList.push_back(info); - - tok = tok2; - } - - // check if in space - else if (info) - { - // check for end of space - if (tok == info->classEnd) - { - info = info->nestedIn; - continue; - } - - // check if in class or structure - else if (info->type == SpaceInfo::Class || info->type == SpaceInfo::Struct) - { - const Token *funcStart = 0; - const Token *argStart = 0; - - // What section are we in.. - if (tok->str() == "private:") - info->access = Private; - else if (tok->str() == "protected:") - info->access = Protected; - else if (tok->str() == "public:") - info->access = Public; - else if (Token::Match(tok, "public|protected|private %var% :")) - { - if (tok->str() == "private") - info->access = Private; - else if (tok->str() == "protected") - info->access = Protected; - else if (tok->str() == "public") - info->access = Public; - - tok = tok->tokAt(2); - } - - // class function? - else if (tok->previous()->str() != "::" && isFunction(tok, &funcStart, &argStart)) - { - Func function; - - // save the function definition argument start '(' - function.argDef = argStart; - - // save the access type - function.access = info->access; - - // save the function name location - function.tokenDef = funcStart; - - // operator function - if (function.tokenDef->previous()->str() == "operator") - { - function.isOperator = true; - - // 'operator =' is special - if (function.tokenDef->str() == "=") - function.type = Func::OperatorEqual; - } - - // class constructor/destructor - else if (function.tokenDef->str() == info->className) - { - if (function.tokenDef->previous()->str() == "~") - function.type = Func::Destructor; - else if ((Token::Match(function.tokenDef, "%var% ( const %var% & )") || - Token::Match(function.tokenDef, "%var% ( const %var% & %var% )")) && - function.tokenDef->strAt(3) == info->className) - function.type = Func::CopyConstructor; - else - function.type = Func::Constructor; - - if (function.tokenDef->previous()->str() == "explicit") - function.isExplicit = true; - } - - // function returning function pointer - else if (tok->str() == "(") - { - function.retFuncPtr = true; - } - - const Token *tok1 = tok; - - // look for end of previous statement - while (tok1->previous() && !Token::Match(tok1->previous(), ";|}|{|public:|protected:|private:")) - { - // virtual function - if (tok1->previous()->str() == "virtual") - { - function.isVirtual = true; - break; - } - - // static function - else if (tok1->previous()->str() == "static") - { - function.isStatic = true; - break; - } - - // friend function - else if (tok1->previous()->str() == "friend") - { - function.isFriend = true; - break; - } - - tok1 = tok1->previous(); - } - - const Token *end; - - if (!function.retFuncPtr) - end = function.argDef->link(); - else - end = tok->link()->next()->link(); - - // const function - if (end->next()->str() == "const") - function.isConst = true; - - // pure virtual function - if (Token::Match(end, ") const| = 0 ;")) - function.isPure = true; - - // count the number of constructors - if (function.type == Func::Constructor || function.type == Func::CopyConstructor) - info->numConstructors++; - - // assume implementation is inline (definition and implementation same) - function.token = function.tokenDef; - - // out of line function - if (Token::Match(end, ") const| ;") || - Token::Match(end, ") const| = 0 ;")) - { - // find the function implementation later - tok = end->next(); - - info->functionList.push_back(function); - } - - // inline function - else - { - function.isInline = true; - function.hasBody = true; - function.arg = function.argDef; - - info->functionList.push_back(function); - - const Token *tok2 = funcStart; - - addNewFunction(&info, &tok2); - - tok = tok2; - } - } - - // nested class function? - else if (tok->previous()->str() == "::" && isFunction(tok, &funcStart, &argStart)) - addFunction(&info, &tok, argStart); - - // friend class declaration? - else if (Token::Match(tok, "friend class| %any% ;")) - { - FriendInfo friendInfo; - - friendInfo.name = tok->strAt(1) == "class" ? tok->strAt(2) : tok->strAt(1); - /** @todo fill this in later after parsing is complete */ - friendInfo.spaceInfo = 0; - - info->friendList.push_back(friendInfo); - } - } - else if (info->type == SpaceInfo::Namespace) - addIfFunction(&info, &tok); - } - - // not in SpaceInfo - else - addIfFunction(&info, &tok); - } - - std::list::iterator it; - - for (it = spaceInfoList.begin(); it != spaceInfoList.end(); ++it) - { - info = *it; - - // skip namespaces and functions - if (info->type == SpaceInfo::Namespace || info->type == SpaceInfo::Function) - continue; - - // finish filling in base class info - for (unsigned int i = 0; i < info->derivedFrom.size(); ++i) - { - std::list::iterator it1; - - for (it1 = spaceInfoList.begin(); it1 != spaceInfoList.end(); ++it1) - { - SpaceInfo *spaceInfo = *it1; - - /** @todo handle derived base classes and namespaces */ - if (spaceInfo->type == SpaceInfo::Class || spaceInfo->type == SpaceInfo::Struct) - { - // do class names match? - if (spaceInfo->className == info->derivedFrom[i].name) - { - // are they in the same namespace or different namespaces with same name? - if ((spaceInfo->nestedIn == info->nestedIn) || - ((spaceInfo->nestedIn && spaceInfo->nestedIn->type == SpaceInfo::Namespace) && - (info->nestedIn && info->nestedIn->type == SpaceInfo::Namespace) && - (spaceInfo->nestedIn->className == info->nestedIn->className))) - { - info->derivedFrom[i].spaceInfo = spaceInfo; - break; - } - } - } - } - } - - // find variables - info->getVarList(); - } -} - -CheckClass::~CheckClass() -{ - std::list::iterator it; - - for (it = spaceInfoList.begin(); it != spaceInfoList.end(); ++it) - delete *it; -} - -const Token *CheckClass::initBaseInfo(SpaceInfo *info, const Token *tok) -{ - // goto initial '{' - const Token *tok2 = tok->tokAt(2); - int level = 0; - while (tok2 && tok2->str() != "{") - { - // skip unsupported templates - if (tok2->str() == "<") - level++; - else if (tok2->str() == ">") - level--; - - // check for base classes - else if (level == 0 && Token::Match(tok2, ":|,")) - { - BaseInfo base; - - tok2 = tok2->next(); - - if (tok2->str() == "public") - { - base.access = Public; - tok2 = tok2->next(); - } - else if (tok2->str() == "protected") - { - base.access = Protected; - tok2 = tok2->next(); - } - else if (tok2->str() == "private") - { - base.access = Private; - tok2 = tok2->next(); - } - else - { - if (tok->str() == "class") - base.access = Private; - else if (tok->str() == "struct") - base.access = Public; - } - - // handle derived base classes - while (Token::Match(tok2, "%var% ::")) - { - base.name += tok2->str(); - base.name += " :: "; - tok2 = tok2->tokAt(2); - } - - base.name += tok2->str(); - - base.spaceInfo = 0; - - // save pattern for base class name - info->derivedFrom.push_back(base); - } - tok2 = tok2->next(); - } - - return tok2; -} -//--------------------------------------------------------------------------- - -CheckClass::SpaceInfo::SpaceInfo(CheckClass *check_, const Token *classDef_, CheckClass::SpaceInfo *nestedIn_) : - check(check_), - classDef(classDef_), - classStart(NULL), - classEnd(NULL), - nestedIn(nestedIn_), - numConstructors(0) -{ - if (classDef->str() == "class") - { - type = SpaceInfo::Class; - className = classDef->next()->str(); - access = Private; - } - else if (classDef->str() == "struct") - { - type = SpaceInfo::Struct; - className = classDef->next()->str(); - access = Public; - } - else if (classDef->str() == "union") - { - type = SpaceInfo::Union; - className = classDef->next()->str(); - access = Public; - } - else if (classDef->str() == "namespace") - { - type = SpaceInfo::Namespace; - className = classDef->next()->str(); - access = Public; - } - else - { - type = SpaceInfo::Function; - className = classDef->str(); - access = Public; - } - - if (nestedIn) - nestedIn->nestedList.push_back(this); -} - -void CheckClass::SpaceInfo::getVarList() -{ - // Get variable list.. - unsigned int indentlevel = 0; - AccessControl varaccess = type == Struct ? Public : Private; - for (const Token *tok = classStart; tok; tok = tok->next()) - { - if (!tok->next()) - break; - - if (tok->str() == "{") - ++indentlevel; - else if (tok->str() == "}") - { - if (indentlevel <= 1) - break; - --indentlevel; - } - - if (indentlevel != 1) - continue; - - // Borland C++: Skip all variables in the __published section. - // These are automaticly initialized. - if (tok->str() == "__published:") - { - for (; tok; tok = tok->next()) - { - if (tok->str() == "{") - tok = tok->link(); - if (Token::Match(tok->next(), "private:|protected:|public:")) - break; - } - if (tok) - continue; - else - break; - } - - // "private:" "public:" "protected:" etc - bool b = false; - if (tok->str() == "public:") - { - varaccess = Public; - b = true; - } - else if (tok->str() == "protected:") - { - varaccess = Protected; - b = true; - } - else if (tok->str() == "private:") - { - varaccess = Private; - b = true; - } - - // Search for start of statement.. - if (! Token::Match(tok, "[;{}]") && ! b) - continue; - - // This is the start of a statement - const Token *next = tok->next(); - const Token *vartok = 0; - - // If next token contains a ":".. it is not part of a variable declaration - if (next->str().find(":") != std::string::npos) - continue; - - // Is it a forward declaration? - if (Token::Match(next, "class|struct|union %var% ;")) - { - tok = tok->tokAt(2); - continue; - } - - // It it a nested class or structure? - if (Token::Match(next, "class|struct|union %type% :|{")) - { - tok = tok->tokAt(2); - while (tok->str() != "{") - tok = tok->next(); - // skip implementation - tok = tok->link(); - continue; - } - - // Borland C++: Ignore properties.. - if (next->str() == "__property") - continue; - - // Is it const..? - if (next->str() == "const") - { - next = next->next(); - } - - // Is it a static variable? - const bool isStatic(Token::simpleMatch(next, "static")); - if (isStatic) - { - next = next->next(); - } - - // Is it a mutable variable? - const bool isMutable(Token::simpleMatch(next, "mutable")); - if (isMutable) - { - next = next->next(); - } - - // Is it const..? - if (next->str() == "const") - { - next = next->next(); - } - - // Is it a variable declaration? - bool isClass = false; - if (Token::Match(next, "%type% %var% ;|:")) - { - if (!next->isStandardType()) - isClass = true; - - vartok = next->tokAt(1); - } - - // Structure? - else if (Token::Match(next, "struct|union %type% %var% ;")) - { - vartok = next->tokAt(2); - } - - // Pointer? - else if (Token::Match(next, "%type% * %var% ;")) - vartok = next->tokAt(2); - else if (Token::Match(next, "%type% %type% * %var% ;")) - vartok = next->tokAt(3); - else if (Token::Match(next, "%type% :: %type% * %var% ;")) - vartok = next->tokAt(4); - else if (Token::Match(next, "%type% :: %type% :: %type% * %var% ;")) - vartok = next->tokAt(6); - - // Array? - else if (Token::Match(next, "%type% %var% [") && next->next()->str() != "operator") - { - if (!next->isStandardType()) - isClass = true; - - vartok = next->tokAt(1); - } - - // Pointer array? - else if (Token::Match(next, "%type% * %var% [")) - vartok = next->tokAt(2); - else if (Token::Match(next, "%type% :: %type% * %var% [")) - vartok = next->tokAt(4); - else if (Token::Match(next, "%type% :: %type% :: %type% * %var% [")) - vartok = next->tokAt(6); - - // std::string.. - else if (Token::Match(next, "%type% :: %type% %var% ;")) - { - isClass = true; - vartok = next->tokAt(3); - } - else if (Token::Match(next, "%type% :: %type% :: %type% %var% ;")) - { - isClass = true; - vartok = next->tokAt(5); - } - - // Container.. - else if (Token::Match(next, "%type% :: %type% <") || - Token::Match(next, "%type% <")) - { - // find matching ">" - int level = 0; - for (; next; next = next->next()) - { - if (next->str() == "<") - level++; - else if (next->str() == ">") - { - level--; - if (level == 0) - break; - } - } - if (next && Token::Match(next, "> %var% ;")) - { - isClass = true; - vartok = next->tokAt(1); - } - else if (next && Token::Match(next, "> * %var% ;")) - vartok = next->tokAt(2); - } - - // If the vartok was set in the if-blocks above, create a entry for this variable.. - if (vartok && vartok->str() != "operator") - { - if (vartok->varId() == 0 && check->_settings->debugwarnings) - { - check->reportError(vartok, Severity::debug, "debug", "CheckClass::SpaceInfo::getVarList found variable \'" + vartok->str() + "\' with varid 0."); - } - - addVar(vartok, varaccess, isMutable, isStatic, isClass); - } - } -} - -//--------------------------------------------------------------------------- - -void CheckClass::SpaceInfo::assignVar(const std::string &varname) -{ - std::list::iterator i; - - for (i = varlist.begin(); i != varlist.end(); ++i) - { - if (i->token->str() == varname) - { - i->assign = true; - return; - } - } -} - -void CheckClass::SpaceInfo::initVar(const std::string &varname) -{ - std::list::iterator i; - - for (i = varlist.begin(); i != varlist.end(); ++i) - { - if (i->token->str() == varname) - { - i->init = true; - return; - } - } -} - -void CheckClass::SpaceInfo::assignAllVar() -{ - std::list::iterator i; - - for (i = varlist.begin(); i != varlist.end(); ++i) - i->assign = true; -} - -void CheckClass::SpaceInfo::clearAllVar() -{ - std::list::iterator i; - - for (i = varlist.begin(); i != varlist.end(); ++i) - { - i->assign = false; - i->init = false; - } -} - -//--------------------------------------------------------------------------- - -bool CheckClass::SpaceInfo::isBaseClassFunc(const Token *tok) -{ - // Iterate through each base class... - for (unsigned int i = 0; i < derivedFrom.size(); ++i) - { - const SpaceInfo *info = derivedFrom[i].spaceInfo; - - // Check if base class exists in database - if (info) - { - std::list::const_iterator it; - - for (it = info->functionList.begin(); it != info->functionList.end(); ++it) - { - if (it->tokenDef->str() == tok->str()) - return true; - } - } - - // Base class not found so assume it is in it. - else - return true; - } - - return false; -} - -void CheckClass::SpaceInfo::initializeVarList(const Func &func, std::list &callstack) -{ - bool Assign = false; - unsigned int indentlevel = 0; - const Token *ftok = func.token; - - for (; ftok; ftok = ftok->next()) - { - if (!ftok->next()) - break; - - // Class constructor.. initializing variables like this - // clKalle::clKalle() : var(value) { } - if (indentlevel == 0) - { - if (Assign && Token::Match(ftok, "%var% (")) - { - initVar(ftok->str()); - - // assignment in the initializer.. - // : var(value = x) - if (Token::Match(ftok->tokAt(2), "%var% =")) - assignVar(ftok->strAt(2)); - } - - Assign |= (ftok->str() == ":"); - } - - - if (ftok->str() == "{") - { - ++indentlevel; - Assign = false; - } - - else if (ftok->str() == "}") - { - if (indentlevel <= 1) - break; - --indentlevel; - } - - if (indentlevel < 1) - continue; - - // Variable getting value from stream? - if (Token::Match(ftok, ">> %var%")) - { - assignVar(ftok->strAt(1)); - } - - // Before a new statement there is "[{};)=]" - if (! Token::Match(ftok, "[{};()=]")) - continue; - - if (Token::simpleMatch(ftok, "( !")) - ftok = ftok->next(); - - // Using the operator= function to initialize all variables.. - if (Token::simpleMatch(ftok->next(), "* this = ")) - { - assignAllVar(); - break; - } - - if (Token::Match(ftok->next(), "%var% . %var% (")) - ftok = ftok->tokAt(2); - - if (!Token::Match(ftok->next(), "%var%") && - !Token::Match(ftok->next(), "this . %var%") && - !Token::Match(ftok->next(), "* %var% =") && - !Token::Match(ftok->next(), "( * this ) . %var%")) - continue; - - // Goto the first token in this statement.. - ftok = ftok->next(); - - // Skip "( * this )" - if (Token::simpleMatch(ftok, "( * this ) .")) - { - ftok = ftok->tokAt(5); - } - - // Skip "this->" - if (Token::simpleMatch(ftok, "this .")) - ftok = ftok->tokAt(2); - - // Skip "classname :: " - if (Token::Match(ftok, "%var% ::")) - ftok = ftok->tokAt(2); - - // Clearing all variables.. - if (Token::simpleMatch(ftok, "memset ( this ,")) - { - assignAllVar(); - return; - } - - // Clearing array.. - else if (Token::Match(ftok, "memset ( %var% ,")) - { - assignVar(ftok->strAt(2)); - ftok = ftok->next()->link(); - continue; - } - - // Calling member function? - else if (Token::Match(ftok, "%var% (") && ftok->str() != "if") - { - // Passing "this" => assume that everything is initialized - for (const Token *tok2 = ftok->next()->link(); tok2 && tok2 != ftok; tok2 = tok2->previous()) - { - if (tok2->str() == "this") - { - assignAllVar(); - return; - } - } - - // recursive call / calling overloaded function - // assume that all variables are initialized - if (std::find(callstack.begin(), callstack.end(), ftok->str()) != callstack.end()) - { - assignAllVar(); - return; - } - - // check if member function - std::list::const_iterator it; - for (it = functionList.begin(); it != functionList.end(); ++it) - { - if (ftok->str() == it->tokenDef->str() && it->type != Func::Constructor) - break; - } - - // member function found - if (it != functionList.end()) - { - // member function has implementation - if (it->hasBody) - { - // initialize variable use list using member function - callstack.push_back(ftok->str()); - initializeVarList(*it, callstack); - callstack.pop_back(); - } - - // there is a called member function, but it has no implementation, so we assume it initializes everything - else - { - assignAllVar(); - } - } - - // not member function - else - { - // could be a base class virtual function, so we assume it initializes everything - if (func.type != Func::Constructor && isBaseClassFunc(ftok)) - { - /** @todo False Negative: we should look at the base class functions to see if they - * call any derived class virtual functions that change the derived class state - */ - assignAllVar(); - } - - // has friends, so we assume it initializes everything - if (!friendList.empty()) - assignAllVar(); - - // the function is external and it's neither friend nor inherited virtual function. - // assume all variables that are passed to it are initialized.. - else - { - unsigned int indentlevel2 = 0; - for (const Token *tok = ftok->tokAt(2); tok; tok = tok->next()) - { - if (tok->str() == "(") - ++indentlevel2; - else if (tok->str() == ")") - { - if (indentlevel2 == 0) - break; - --indentlevel2; - } - if (tok->isName()) - { - assignVar(tok->str()); - } - } - } - } - } - - // Assignment of member variable? - else if (Token::Match(ftok, "%var% =")) - { - assignVar(ftok->str()); - } - - // Assignment of array item of member variable? - else if (Token::Match(ftok, "%var% [ %any% ] =")) - { - assignVar(ftok->str()); - } - - // Assignment of array item of member variable? - else if (Token::Match(ftok, "%var% [ %any% ] [ %any% ] =")) - { - assignVar(ftok->str()); - } - - // Assignment of array item of member variable? - else if (Token::Match(ftok, "* %var% =")) - { - assignVar(ftok->next()->str()); - } - - // Assignment of struct member of member variable? - else if (Token::Match(ftok, "%var% . %any% =")) - { - assignVar(ftok->str()); - } - - // The functions 'clear' and 'Clear' are supposed to initialize variable. - if (Token::Match(ftok, "%var% . clear|Clear (")) - { - assignVar(ftok->str()); - } - } -} - -bool CheckClass::argsMatch(const Token *first, const Token *second, const std::string &path, unsigned int depth) const -{ - bool match = false; - while (first->str() == second->str()) - { - // at end of argument list - if (first->str() == ")") - { - match = true; - break; - } - - // skip default value assignment - else if (first->next()->str() == "=") - first = first->tokAt(2); - - // definition missing variable name - else if (first->next()->str() == "," && second->next()->str() != ",") - second = second->next(); - else if (first->next()->str() == ")" && second->next()->str() != ")") - second = second->next(); - - // function missing variable name - else if (second->next()->str() == "," && first->next()->str() != ",") - first = first->next(); - else if (second->next()->str() == ")" && first->next()->str() != ")") - first = first->next(); - - // argument list has different number of arguments - else if (second->str() == ")") - break; - - // variable names are different - else if ((Token::Match(first->next(), "%var% ,|)|=") && - Token::Match(second->next(), "%var% ,|)")) && - (first->next()->str() != second->next()->str())) - { - // skip variable names - first = first->next(); - second = second->next(); - - // skip default value assignment - if (first->next()->str() == "=") - first = first->tokAt(2); - } - - // variable with class path - else if (depth && Token::Match(first->next(), "%var%")) - { - std::string param = path + first->next()->str(); - - if (Token::Match(second->next(), param.c_str())) - { - second = second->tokAt(int(depth) * 2); - } - else if (depth > 1) - { - std::string short_path = path; - - // remove last " :: " - short_path.resize(short_path.size() - 4); - - // remove last name - while (!short_path.empty() && short_path[short_path.size() - 1] != ' ') - short_path.resize(short_path.size() - 1); - - param = short_path + first->next()->str(); - if (Token::Match(second->next(), param.c_str())) - { - second = second->tokAt((int(depth) - 1) * 2); - } - } - } - - first = first->next(); - second = second->next(); - } - - return match; + symbolDatabase = new SymbolDatabase(_tokenizer, _settings, _errorLogger); } //--------------------------------------------------------------------------- @@ -1281,24 +73,24 @@ void CheckClass::constructors() createSymbolDatabase(); - std::list::iterator i; + std::list::iterator i; - for (i = spaceInfoList.begin(); i != spaceInfoList.end(); ++i) + for (i = symbolDatabase->spaceInfoList.begin(); i != symbolDatabase->spaceInfoList.end(); ++i) { - SpaceInfo *info = *i; + SymbolDatabase::SpaceInfo *info = *i; // don't check namespaces - if (info->type == SpaceInfo::Namespace || info->type == SpaceInfo::Function) + if (info->type == SymbolDatabase::SpaceInfo::Namespace || info->type == SymbolDatabase::SpaceInfo::Function) continue; // There are no constructors. if (info->numConstructors == 0) { // If there is a private variable, there should be a constructor.. - std::list::const_iterator var; + std::list::const_iterator var; for (var = info->varlist.begin(); var != info->varlist.end(); ++var) { - if (var->access == Private && !var->isClass && !var->isStatic) + if (var->access == SymbolDatabase::Private && !var->isClass && !var->isStatic) { noConstructorError(info->classDef, info->className, info->classDef->str() == "struct"); break; @@ -1306,11 +98,11 @@ void CheckClass::constructors() } } - std::list::const_iterator it; + std::list::const_iterator it; for (it = info->functionList.begin(); it != info->functionList.end(); ++it) { - if (!it->hasBody || !(it->type == Func::Constructor || it->type == Func::CopyConstructor || it->type == Func::OperatorEqual)) + if (!it->hasBody || !(it->type == SymbolDatabase::Func::Constructor || it->type == SymbolDatabase::Func::CopyConstructor || it->type == SymbolDatabase::Func::OperatorEqual)) continue; // Mark all variables not used @@ -1320,18 +112,18 @@ void CheckClass::constructors() info->initializeVarList(*it, callstack); // Check if any variables are uninitialized - std::list::const_iterator var; + std::list::const_iterator var; for (var = info->varlist.begin(); var != info->varlist.end(); ++var) { // skip classes for regular constructor - if (var->isClass && it->type == Func::Constructor) + if (var->isClass && it->type == SymbolDatabase::Func::Constructor) continue; if (var->assign || var->init || var->isStatic) continue; // It's non-static and it's not initialized => error - if (it->type == Func::OperatorEqual) + if (it->type == SymbolDatabase::Func::OperatorEqual) { const Token *operStart = 0; if (it->token->str() == "=") @@ -1352,7 +144,7 @@ void CheckClass::constructors() if (classNameUsed) operatorEqVarError(it->token, info->className, var->token->str()); } - else if (it->access != Private) + else if (it->access != SymbolDatabase::Private) uninitVarError(it->token, info->className, var->token->str()); } } @@ -1379,14 +171,14 @@ void CheckClass::privateFunctions() createSymbolDatabase(); - std::list::iterator i; + std::list::iterator i; - for (i = spaceInfoList.begin(); i != spaceInfoList.end(); ++i) + for (i = symbolDatabase->spaceInfoList.begin(); i != symbolDatabase->spaceInfoList.end(); ++i) { - SpaceInfo *info = *i; + SymbolDatabase::SpaceInfo *info = *i; // don't check namespaces - if (info->type == SpaceInfo::Namespace || info->type == SpaceInfo::Function) + if (info->type == SymbolDatabase::SpaceInfo::Namespace || info->type == SymbolDatabase::SpaceInfo::Function) continue; // dont check derived classes @@ -1398,13 +190,13 @@ void CheckClass::privateFunctions() // check that the whole class implementation is seen bool whole = true; - std::list::const_iterator func; + std::list::const_iterator func; for (func = info->functionList.begin(); func != info->functionList.end(); ++func) { if (!func->hasBody) { // empty private copy constructors and assignment operators are OK - if ((func->type == Func::CopyConstructor || func->type == Func::OperatorEqual) && func->access == Private) + if ((func->type == SymbolDatabase::Func::CopyConstructor || func->type == SymbolDatabase::Func::OperatorEqual) && func->access == SymbolDatabase::Private) continue; whole = false; @@ -1424,8 +216,8 @@ void CheckClass::privateFunctions() for (func = info->functionList.begin(); func != info->functionList.end(); ++func) { // Get private functions.. - if (func->type == Func::Function && - func->access == Private && func->hasBody) + if (func->type == SymbolDatabase::Func::Function && + func->access == SymbolDatabase::Private && func->hasBody) FuncList.push_back(func->tokenDef); } } @@ -1633,15 +425,15 @@ void CheckClass::operatorEq() createSymbolDatabase(); - std::list::const_iterator i; + std::list::const_iterator i; - for (i = spaceInfoList.begin(); i != spaceInfoList.end(); ++i) + for (i = symbolDatabase->spaceInfoList.begin(); i != symbolDatabase->spaceInfoList.end(); ++i) { - std::list::const_iterator it; + std::list::const_iterator it; for (it = (*i)->functionList.begin(); it != (*i)->functionList.end(); ++it) { - if (it->type == Func::OperatorEqual && it->access != Private) + if (it->type == SymbolDatabase::Func::OperatorEqual && it->access != SymbolDatabase::Private) { if (it->token->strAt(-2) == "void") operatorEqReturnError(it->token->tokAt(-2)); @@ -1655,7 +447,7 @@ void CheckClass::operatorEq() // operator= should return a reference to *this //--------------------------------------------------------------------------- -void CheckClass::checkReturnPtrThis(const SpaceInfo *info, const Func *func, const Token *tok, const Token *last) +void CheckClass::checkReturnPtrThis(const SymbolDatabase::SpaceInfo *info, const SymbolDatabase::Func *func, const Token *tok, const Token *last) { bool foundReturn = false; @@ -1673,13 +465,13 @@ void CheckClass::checkReturnPtrThis(const SpaceInfo *info, const Func *func, con if (Token::Match(tok->tokAt(1), "%any% (") && tok->tokAt(2)->link()->next()->str() == ";") { - std::list::const_iterator it; + std::list::const_iterator it; // check if it is a member function for (it = info->functionList.begin(); it != info->functionList.end(); ++it) { // check for a regular function with the same name and a bofy - if (it->type == Func::Function && it->hasBody && + if (it->type == SymbolDatabase::Func::Function && it->hasBody && it->token->str() == tok->next()->str()) { // check for the proper return type @@ -1712,19 +504,19 @@ void CheckClass::operatorEqRetRefThis() createSymbolDatabase(); - std::list::const_iterator i; + std::list::const_iterator i; - for (i = spaceInfoList.begin(); i != spaceInfoList.end(); ++i) + for (i = symbolDatabase->spaceInfoList.begin(); i != symbolDatabase->spaceInfoList.end(); ++i) { - const SpaceInfo *info = *i; + const SymbolDatabase::SpaceInfo *info = *i; - if (info->type == SpaceInfo::Class || info->type == SpaceInfo::Struct) + if (info->type == SymbolDatabase::SpaceInfo::Class || info->type == SymbolDatabase::SpaceInfo::Struct) { - std::list::const_iterator func; + std::list::const_iterator func; for (func = info->functionList.begin(); func != info->functionList.end(); ++func) { - if (func->type == Func::OperatorEqual && func->hasBody) + if (func->type == SymbolDatabase::Func::OperatorEqual && func->hasBody) { // make sure return signature is correct if (Token::Match(func->tokenDef->tokAt(-4), ";|}|{|public:|protected:|private: %type% &") && @@ -1872,12 +664,12 @@ void CheckClass::operatorEqToSelf() createSymbolDatabase(); - std::list::const_iterator i; + std::list::const_iterator i; - for (i = spaceInfoList.begin(); i != spaceInfoList.end(); ++i) + for (i = symbolDatabase->spaceInfoList.begin(); i != symbolDatabase->spaceInfoList.end(); ++i) { - const SpaceInfo *info = *i; - std::list::const_iterator it; + const SymbolDatabase::SpaceInfo *info = *i; + std::list::const_iterator it; // skip classes with multiple inheritance if (info->derivedFrom.size() > 1) @@ -1885,7 +677,7 @@ void CheckClass::operatorEqToSelf() for (it = info->functionList.begin(); it != info->functionList.end(); ++it) { - if (it->type == Func::OperatorEqual && it->hasBody) + if (it->type == SymbolDatabase::Func::OperatorEqual && it->hasBody) { // make sure return signature is correct if (Token::Match(it->tokenDef->tokAt(-4), ";|}|{|public:|protected:|private: %type% &") && @@ -1943,18 +735,18 @@ void CheckClass::virtualDestructor() createSymbolDatabase(); - std::list::const_iterator i; + std::list::const_iterator i; - for (i = spaceInfoList.begin(); i != spaceInfoList.end(); ++i) + for (i = symbolDatabase->spaceInfoList.begin(); i != symbolDatabase->spaceInfoList.end(); ++i) { - const SpaceInfo *info = *i; + const SymbolDatabase::SpaceInfo *info = *i; // Skip base classes and namespaces if (info->derivedFrom.empty()) continue; // Find the destructor - const Func *destructor = info->getDestructor(); + const SymbolDatabase::Func *destructor = info->getDestructor(); // Check for destructor with implementation if (!destructor || !destructor->hasBody) @@ -1971,15 +763,15 @@ void CheckClass::virtualDestructor() for (unsigned int j = 0; j < info->derivedFrom.size(); ++j) { // Check if base class is public and exists in database - if (info->derivedFrom[j].access == Public && info->derivedFrom[j].spaceInfo) + if (info->derivedFrom[j].access == SymbolDatabase::Public && info->derivedFrom[j].spaceInfo) { - const SpaceInfo *spaceInfo = info->derivedFrom[j].spaceInfo; + const SymbolDatabase::SpaceInfo *spaceInfo = info->derivedFrom[j].spaceInfo; // Name of base class.. const std::string baseName = spaceInfo->className; // Find the destructor declaration for the base class. - const Func *base_destructor = spaceInfo->getDestructor(); + const SymbolDatabase::Func *base_destructor = spaceInfo->getDestructor(); const Token *base = 0; if (base_destructor) base = base_destructor->token; @@ -2003,7 +795,7 @@ void CheckClass::virtualDestructor() // Make sure that the destructor is public (protected or private // would not compile if inheritance is used in a way that would // cause the bug we are trying to find here.) - if (base_destructor->access == Public) + if (base_destructor->access == SymbolDatabase::Public) virtualDestructorError(base, baseName, derivedClass->str()); } } @@ -2038,70 +830,6 @@ void CheckClass::thisSubtraction() } //--------------------------------------------------------------------------- -// check if this function is defined virtual in the base classes -bool CheckClass::isVirtual(const SpaceInfo *info, const Token *functionToken) const -{ - // check each base class - for (unsigned int i = 0; i < info->derivedFrom.size(); ++i) - { - // check if base class exists in database - if (info->derivedFrom[i].spaceInfo) - { - const SpaceInfo *derivedFrom = info->derivedFrom[i].spaceInfo; - - std::list::const_iterator func; - - // check if function defined in base class - for (func = derivedFrom->functionList.begin(); func != derivedFrom->functionList.end(); ++func) - { - if (func->isVirtual) - { - const Token *tok = func->tokenDef; - - if (tok->str() == functionToken->str()) - { - const Token *temp1 = tok->previous(); - const Token *temp2 = functionToken->previous(); - bool returnMatch = true; - - // check for matching return parameters - while (temp1->str() != "virtual") - { - if (temp1->str() != temp2->str()) - { - returnMatch = false; - break; - } - - temp1 = temp1->previous(); - temp2 = temp2->previous(); - } - - // check for matching function parameters - if (returnMatch && argsMatch(tok->tokAt(2), functionToken->tokAt(2), std::string(""), 0)) - { - return true; - } - } - } - } - - if (!derivedFrom->derivedFrom.empty()) - { - if (isVirtual(derivedFrom, functionToken)) - return true; - } - } - else - { - // unable to find base class so assume it has a virtual function - return true; - } - } - - return false; -} - // Can a function be const? void CheckClass::checkConst() { @@ -2116,18 +844,18 @@ void CheckClass::checkConst() createSymbolDatabase(); - std::list::iterator it; + std::list::iterator it; - for (it = spaceInfoList.begin(); it != spaceInfoList.end(); ++it) + for (it = symbolDatabase->spaceInfoList.begin(); it != symbolDatabase->spaceInfoList.end(); ++it) { - SpaceInfo *info = *it; + SymbolDatabase::SpaceInfo *info = *it; - std::list::const_iterator func; + std::list::const_iterator func; for (func = info->functionList.begin(); func != info->functionList.end(); ++func) { // does the function have a body? - if (func->type == Func::Function && func->hasBody && !func->isFriend && !func->isStatic && !func->isConst && !func->isVirtual) + if (func->type == SymbolDatabase::Func::Function && func->hasBody && !func->isFriend && !func->isStatic && !func->isConst && !func->isVirtual) { // get last token of return type const Token *previous = func->tokenDef->isName() ? func->token->previous() : func->token->tokAt(-2); @@ -2187,15 +915,15 @@ void CheckClass::checkConst() // check if base class function is virtual if (!info->derivedFrom.empty()) { - if (isVirtual(info, func->tokenDef)) + if (symbolDatabase->isVirtualFunc(info, func->tokenDef)) continue; } // if nothing non-const was found. write error.. - if (checkConstFunc(info, paramEnd)) + if (symbolDatabase->checkConstFunc(info, paramEnd)) { std::string classname = info->className; - SpaceInfo *nest = info->nestedIn; + SymbolDatabase::SpaceInfo *nest = info->nestedIn; while (nest) { classname = std::string(nest->className + "::" + classname); @@ -2220,182 +948,6 @@ void CheckClass::checkConst() } } -bool CheckClass::isMemberVar(const SpaceInfo *info, const Token *tok) -{ - const Token *tok1 = tok; - - while (tok->previous() && !Token::Match(tok->previous(), "}|{|;|public:|protected:|private:|return|:|?")) - { - if (Token::Match(tok->previous(), "* this")) - return true; - - tok = tok->previous(); - } - - if (tok->str() == "this") - return true; - - if (Token::Match(tok, "( * %var% ) [") || (Token::Match(tok, "( * %var% ) <<") && tok1->next()->str() == "<<")) - tok = tok->tokAt(2); - - // ignore class namespace - if (tok->str() == info->className && tok->next()->str() == "::") - tok = tok->tokAt(2); - - std::list::const_iterator var; - for (var = info->varlist.begin(); var != info->varlist.end(); ++var) - { - if (var->token->str() == tok->str()) - { - return !var->isMutable; - } - } - - // not found in this class - if (!info->derivedFrom.empty()) - { - // check each base class - for (unsigned int i = 0; i < info->derivedFrom.size(); ++i) - { - // find the base class - const SpaceInfo *spaceInfo = info->derivedFrom[i].spaceInfo; - - // find the function in the base class - if (spaceInfo) - { - if (isMemberVar(spaceInfo, tok)) - return true; - } - } - } - - return false; -} - -bool CheckClass::isConstMemberFunc(const SpaceInfo *info, const Token *tok) -{ - std::list::const_iterator func; - - for (func = info->functionList.begin(); func != info->functionList.end(); ++func) - { - if (func->tokenDef->str() == tok->str() && func->isConst) - return true; - } - - // not found in this class - if (!info->derivedFrom.empty()) - { - // check each base class - for (unsigned int i = 0; i < info->derivedFrom.size(); ++i) - { - // find the base class - const SpaceInfo *spaceInfo = info->derivedFrom[i].spaceInfo; - - // find the function in the base class - if (spaceInfo) - { - if (isConstMemberFunc(spaceInfo, tok)) - return true; - } - } - } - - return false; -} - -bool CheckClass::checkConstFunc(const SpaceInfo *info, const Token *tok) -{ - // if the function doesn't have any assignment nor function call, - // it can be a const function.. - unsigned int indentlevel = 0; - bool isconst = true; - for (const Token *tok1 = tok; tok1; tok1 = tok1->next()) - { - if (tok1->str() == "{") - ++indentlevel; - else if (tok1->str() == "}") - { - if (indentlevel <= 1) - break; - --indentlevel; - } - - // assignment.. = += |= .. - else if (tok1->str() == "=" || - (tok1->str().find("=") == 1 && - tok1->str().find_first_of("") == std::string::npos)) - { - if (tok1->previous()->varId() == 0 && !info->derivedFrom.empty()) - { - isconst = false; - break; - } - else if (isMemberVar(info, tok1->previous())) - { - isconst = false; - break; - } - else if (tok1->previous()->str() == "]") - { - // TODO: I assume that the assigned variable is a member variable - // don't assume it - isconst = false; - break; - } - else if (tok1->next()->str() == "this") - { - isconst = false; - break; - } - - // FIXME: I assume that a member union/struct variable is assigned. - else if (Token::Match(tok1->tokAt(-2), ". %var%")) - { - isconst = false; - break; - } - } - - // streaming: << - else if (tok1->str() == "<<" && isMemberVar(info, tok1->previous())) - { - isconst = false; - break; - } - - // increment/decrement (member variable?).. - else if (Token::Match(tok1, "++|--")) - { - isconst = false; - break; - } - - // function call.. - else if (Token::Match(tok1, "%var% (") && - !(Token::Match(tok1, "return|c_str|if|string") || tok1->isStandardType())) - { - if (!isConstMemberFunc(info, tok1)) - { - isconst = false; - break; - } - } - else if (Token::Match(tok1, "%var% < %any% > (")) - { - isconst = false; - break; - } - - // delete.. - else if (tok1->str() == "delete") - { - isconst = false; - break; - } - } - - return isconst; -} void CheckClass::checkConstError(const Token *tok, const std::string &classname, const std::string &funcname) { diff --git a/lib/checkclass.h b/lib/checkclass.h index 49ac6ed3e..28d4c992a 100644 --- a/lib/checkclass.h +++ b/lib/checkclass.h @@ -23,6 +23,7 @@ #include "check.h" #include "settings.h" +#include "symboldatabase.h" class Token; @@ -35,7 +36,7 @@ class CheckClass : public Check { public: /** @brief This constructor is used when registering the CheckClass */ - CheckClass() : Check(), hasSymbolDatabase(false) + CheckClass() : Check(), symbolDatabase(NULL) { } /** @brief This constructor is used when running checks. */ @@ -104,12 +105,6 @@ public: /** @brief can member function be const? */ void checkConst(); - /** - * @brief Access control. This needs to be public, otherwise it - * doesn't work to compile with Borland C++ - */ - enum AccessControl { Public, Protected, Private }; - private: /** * @brief Create symbol database. For performance reasons, only call @@ -117,239 +112,7 @@ private: */ void createSymbolDatabase(); - /** - * @brief Prevent creating symbol database more than once. - * - * Initialize this flag to false in the constructors. If this flag - * is true the createSymbolDatabase should just bail out. If it is - * false the createSymbolDatabase will set it to true and create - * the symbol database. - */ - bool hasSymbolDatabase; - - /** @brief Information about a member variable. Used when checking for uninitialized variables */ - class Var - { - public: - Var(const Token *token_, unsigned int index_, AccessControl access_ = Public, bool mutable_ = false, bool static_ = false, bool class_ = false) - : token(token_), - index(index_), - assign(false), - init(false), - access(access_), - isMutable(mutable_), - isStatic(static_), - isClass(class_) - { - } - - /** @brief variable token */ - const Token *token; - - /** @brief order declared */ - unsigned int index; - - /** @brief has this variable been assigned? */ - bool assign; - - /** @brief has this variable been initialized? */ - bool init; - - /** @brief what section is this variable declared in? */ - AccessControl access; // public/protected/private - - /** @brief is this variable mutable? */ - bool isMutable; - - /** @brief is this variable static? */ - bool isStatic; - - /** @brief is this variable a class (or unknown type)? */ - bool isClass; - }; - - class Func - { - public: - enum Type { Constructor, CopyConstructor, OperatorEqual, Destructor, Function }; - - Func() - : tokenDef(NULL), - argDef(NULL), - token(NULL), - arg(NULL), - access(Public), - hasBody(false), - isInline(false), - isConst(false), - isVirtual(false), - isPure(false), - isStatic(false), - isFriend(false), - isExplicit(false), - isOperator(false), - retFuncPtr(false), - type(Function) - { - } - - const Token *tokenDef; // function name token in class definition - const Token *argDef; // function argument start '(' in class definition - const Token *token; // function name token in implementation - const Token *arg; // function argument start '(' - AccessControl access; // public/protected/private - bool hasBody; // has implementation - bool isInline; // implementation in class definition - bool isConst; // is const - bool isVirtual; // is virtual - bool isPure; // is pure virtual - bool isStatic; // is static - bool isFriend; // is friend - bool isExplicit; // is explicit - bool isOperator; // is operator - bool retFuncPtr; // returns function pointer - Type type; // constructor, destructor, ... - }; - - class SpaceInfo; - - struct BaseInfo - { - AccessControl access; // public/protected/private - std::string name; - SpaceInfo *spaceInfo; - }; - - struct FriendInfo - { - std::string name; - SpaceInfo *spaceInfo; - }; - - class SpaceInfo - { - public: - enum SpaceType { Class, Struct, Union, Namespace, Function }; - - SpaceInfo(CheckClass *check_, const Token *classDef_, SpaceInfo *nestedIn_); - - CheckClass *check; - SpaceType type; - std::string className; - const Token *classDef; // class/struct/union/namespace token - const Token *classStart; // '{' token - const Token *classEnd; // '}' token - std::list functionList; - std::list varlist; - std::vector derivedFrom; - std::list friendList; - SpaceInfo *nestedIn; - std::list nestedList; - AccessControl access; - unsigned int numConstructors; - - /** - * @brief find if name is in nested list - * @param name name of nested space - */ - SpaceInfo * findInNestedList(const std::string & name) - { - std::list::iterator it; - - for (it = nestedList.begin(); it != nestedList.end(); ++it) - { - if ((*it)->className == name) - return (*it); - } - return 0; - } - - /** - * @brief assign a variable in the varlist - * @param varname name of variable to mark assigned - */ - void assignVar(const std::string &varname); - - /** - * @brief initialize a variable in the varlist - * @param varname name of variable to mark initialized - */ - void initVar(const std::string &varname); - - void addVar(const Token *token_, AccessControl access_, bool mutable_, bool static_, bool class_) - { - varlist.push_back(Var(token_, varlist.size(), access_, mutable_, static_, class_)); - } - - /** - * @brief set all variables in list assigned - */ - void assignAllVar(); - - /** - * @brief set all variables in list not assigned and not initialized - */ - void clearAllVar(); - - /** @brief initialize varlist */ - void getVarList(); - - /** - * @brief parse a scope for a constructor or member function and set the "init" flags in the provided varlist - * @param func reference to the function that should be checked - * @param callstack the function doesn't look into recursive function calls. - */ - void initializeVarList(const Func &func, std::list &callstack); - - const Func *getDestructor() const - { - std::list::const_iterator it; - for (it = functionList.begin(); it != functionList.end(); ++it) - { - if (it->type == Func::Destructor) - return &*it; - } - return 0; - } - - /** - * @brief get the number of nested spaces that are not functions - * - * This returns the number of user defined types (class, struct, union) - * that are defined in this user defined type or namespace. - */ - unsigned int getNestedNonFunctions() const - { - unsigned int nested = 0; - std::list::const_iterator ni; - for (ni = nestedList.begin(); ni != nestedList.end(); ++ni) - { - if ((*ni)->type != SpaceInfo::Function) - nested++; - } - return nested; - } - - bool isBaseClassFunc(const Token *tok); - }; - - void addFunction(SpaceInfo **info, const Token **tok, const Token *argStart); - void addNewFunction(SpaceInfo **info, const Token **tok); - void addIfFunction(SpaceInfo **info, const Token **tok); - - /** @brief Information about all namespaces/classes/structrues */ - std::list spaceInfoList; - - bool argsMatch(const Token *first, const Token *second, const std::string &path, unsigned int depth) const; - - bool isMemberVar(const SpaceInfo *info, const Token *tok); - bool isConstMemberFunc(const SpaceInfo *info, const Token *tok); - bool checkConstFunc(const SpaceInfo *info, const Token *tok); - - const Token *initBaseInfo(SpaceInfo *info, const Token *tok); - - /** @brief check if this function is virtual in the base classes */ - bool isVirtual(const SpaceInfo *info, const Token *functionToken) const; + SymbolDatabase *symbolDatabase; // Reporting errors.. void noConstructorError(const Token *tok, const std::string &classname, bool isStruct); @@ -402,7 +165,7 @@ private: } private: - void checkReturnPtrThis(const SpaceInfo *info, const Func *func, const Token *tok, const Token *last); + void checkReturnPtrThis(const SymbolDatabase::SpaceInfo *info, const SymbolDatabase::Func *func, const Token *tok, const Token *last); }; /// @} //--------------------------------------------------------------------------- diff --git a/lib/lib.pri b/lib/lib.pri index 93b3dc6f2..b5232a89d 100644 --- a/lib/lib.pri +++ b/lib/lib.pri @@ -23,6 +23,7 @@ HEADERS += $$PWD/check.h \ $$PWD/path.h \ $$PWD/preprocessor.h \ $$PWD/settings.h \ + $$PWD/symboldatabase.h \ $$PWD/timer.h \ $$PWD/token.h \ $$PWD/tokenize.h @@ -49,6 +50,7 @@ SOURCES += $$PWD/checkautovariables.cpp \ $$PWD/path.cpp \ $$PWD/preprocessor.cpp \ $$PWD/settings.cpp \ + $$PWD/symboldatabase.cpp \ $$PWD/timer.cpp \ $$PWD/token.cpp \ $$PWD/tokenize.cpp