From 27cae2f0d79f09b8107c38098657d3eef9f68780 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sat, 20 Nov 2010 07:26:50 +0100 Subject: [PATCH] Symbol database: add global space and add all global functions and variables to it. Ticket: #2198 --- lib/checkclass.cpp | 43 ++--- lib/symboldatabase.cpp | 379 +++++++++++++++++++++++------------------ lib/symboldatabase.h | 8 +- 3 files changed, 240 insertions(+), 190 deletions(-) diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 7363517b4..53aa59ce4 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -79,8 +79,8 @@ void CheckClass::constructors() { SymbolDatabase::SpaceInfo *info = *i; - // don't check namespaces - if (info->type == SymbolDatabase::SpaceInfo::Namespace || info->type == SymbolDatabase::SpaceInfo::Function) + // only check classes and structures + if (!info->isClassOrStruct()) continue; // There are no constructors. @@ -98,25 +98,25 @@ void CheckClass::constructors() } } - std::list::const_iterator it; + std::list::const_iterator func; - for (it = info->functionList.begin(); it != info->functionList.end(); ++it) + for (func = info->functionList.begin(); func != info->functionList.end(); ++func) { - if (!it->hasBody || !(it->type == SymbolDatabase::Func::Constructor || it->type == SymbolDatabase::Func::CopyConstructor || it->type == SymbolDatabase::Func::OperatorEqual)) + if (!func->hasBody || !(func->type == SymbolDatabase::Func::Constructor || func->type == SymbolDatabase::Func::CopyConstructor || func->type == SymbolDatabase::Func::OperatorEqual)) continue; // Mark all variables not used info->clearAllVar(); std::list callstack; - info->initializeVarList(*it, callstack); + info->initializeVarList(*func, callstack); // Check if any variables are uninitialized 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 == SymbolDatabase::Func::Constructor) + if (var->isClass && func->type == SymbolDatabase::Func::Constructor) continue; if (var->assign || var->init || var->isStatic) @@ -126,13 +126,13 @@ void CheckClass::constructors() continue; // It's non-static and it's not initialized => error - if (it->type == SymbolDatabase::Func::OperatorEqual) + if (func->type == SymbolDatabase::Func::OperatorEqual) { const Token *operStart = 0; - if (it->token->str() == "=") - operStart = it->token->tokAt(1); + if (func->token->str() == "=") + operStart = func->token->tokAt(1); else - operStart = it->token->tokAt(3); + operStart = func->token->tokAt(3); bool classNameUsed = false; for (const Token *operTok = operStart; operTok != operStart->link(); operTok = operTok->next()) @@ -145,10 +145,10 @@ void CheckClass::constructors() } if (classNameUsed) - operatorEqVarError(it->token, info->className, var->token->str()); + operatorEqVarError(func->token, info->className, var->token->str()); } - else if (it->access != SymbolDatabase::Private) - uninitVarError(it->token, info->className, var->token->str()); + else if (func->access != SymbolDatabase::Private) + uninitVarError(func->token, info->className, var->token->str()); } } } @@ -196,8 +196,8 @@ void CheckClass::privateFunctions() { SymbolDatabase::SpaceInfo *info = *i; - // don't check namespaces - if (info->type == SymbolDatabase::SpaceInfo::Namespace || info->type == SymbolDatabase::SpaceInfo::Function) + // only check classes and structures + if (!info->isClassOrStruct()) continue; // dont check derived classes @@ -545,7 +545,8 @@ void CheckClass::operatorEqRetRefThis() { const SymbolDatabase::SpaceInfo *info = *i; - if (info->type == SymbolDatabase::SpaceInfo::Class || info->type == SymbolDatabase::SpaceInfo::Struct) + // only check classes and structures + if (info->isClassOrStruct()) { std::list::const_iterator func; @@ -896,6 +897,10 @@ void CheckClass::checkConst() { SymbolDatabase::SpaceInfo *info = *it; + // only check classes and structures + if (!info->isClassOrStruct()) + continue; + std::list::const_iterator func; for (func = info->functionList.begin(); func != info->functionList.end(); ++func) @@ -905,7 +910,7 @@ void CheckClass::checkConst() { // get last token of return type const Token *previous = func->tokenDef->isName() ? func->token->previous() : func->token->tokAt(-2); - while (previous->str() == "::") + while (previous && previous->str() == "::") previous = previous->tokAt(-2); // does the function return a pointer or reference? @@ -970,7 +975,7 @@ void CheckClass::checkConst() { std::string classname = info->className; SymbolDatabase::SpaceInfo *nest = info->nestedIn; - while (nest) + while (nest && nest->type != SymbolDatabase::SpaceInfo::Global) { classname = std::string(nest->className + "::" + classname); nest = nest->nestedIn; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index a5ed9e217..65d3faa18 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -39,7 +39,8 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti : _tokenizer(tokenizer), _settings(settings), _errorLogger(errorLogger) { // find all namespaces (class,struct and namespace) - SpaceInfo *info = 0; + SpaceInfo *info = new SpaceInfo(this, NULL, NULL); + spaceInfoList.push_back(info); for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { // Locate next class @@ -49,7 +50,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti 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) + if (new_info->isClassOrStruct()) { // goto initial '{' tok2 = initBaseInfo(new_info, tok); @@ -66,8 +67,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti tok = tok2; } - // check if in space - else if (info) + else { // check for end of space if (tok == info->classEnd) @@ -241,13 +241,66 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti info->friendList.push_back(friendInfo); } } - else if (info->type == SpaceInfo::Namespace) - addIfFunction(&info, &tok); - } + else if (info->type == SpaceInfo::Namespace || info->type == SpaceInfo::Global) + { + const Token *funcStart = 0; + const Token *argStart = 0; - // not in SpaceInfo - else - addIfFunction(&info, &tok); + // 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 + { + Func function; + + // save the function definition argument start '(' + function.argDef = argStart; + + // save the access type + function.access = Public; + + // save the function name location + function.tokenDef = funcStart; + function.token = funcStart; + + function.isInline = false; + function.hasBody = true; + function.arg = function.argDef; + function.type = Func::Function; + + info->functionList.push_back(function); + + 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; + } + } + } + } } std::list::iterator it; @@ -440,14 +493,14 @@ bool SymbolDatabase::argsMatch(const Token *first, const Token *second, const st void SymbolDatabase::addFunction(SpaceInfo **info, const Token **tok, const Token *argStart) { - const Token *tok1 = (*tok)->tokAt(-2); + const Token *tok1 = (*tok)->tokAt(-2); // skip class/struct name 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() == "::") + while (tok1 && tok1->previous() && tok1->previous()->str() == "::") { path = tok1->str() + " :: " + path; tok1 = tok1->tokAt(-2); @@ -468,35 +521,28 @@ void SymbolDatabase::addFunction(SpaceInfo **info, const Token **tok, const Toke { 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)) + if (info1->className == tok1->str() && (info1->type != SpaceInfo::Function)) { - SpaceInfo *info2 = info1; - - while (info2 && count > 0) + // do the spaces match (same space) or do their names match (multiple namespaces) + if ((*info == info1->nestedIn) || (*info && info1 && + (*info)->className == info1->nestedIn->className && !(*info)->className.empty() && + (*info)->type == info1->nestedIn->type)) { - count--; - tok1 = tok1->tokAt(2); - info2 = info2->findInNestedList(tok1->str()); - } + SpaceInfo *info2 = info1; - if (count == 0 && info2) - { - match = true; - info1 = info2; + while (info2 && count > 0) + { + count--; + tok1 = tok1->tokAt(2); + info2 = info2->findInNestedList(tok1->str()); + } + + if (count == 0 && info2) + { + match = true; + info1 = info2; + } } } @@ -585,45 +631,6 @@ void SymbolDatabase::addNewFunction(SymbolDatabase::SpaceInfo **info, const Toke } } -void SymbolDatabase::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; - } - } -} - const Token *SymbolDatabase::initBaseInfo(SpaceInfo *info, const Token *tok) { // goto initial '{' @@ -697,7 +704,12 @@ SymbolDatabase::SpaceInfo::SpaceInfo(SymbolDatabase *check_, const Token *classD nestedIn(nestedIn_), numConstructors(0) { - if (classDef->str() == "class") + if (!classDef) + { + type = SpaceInfo::Global; + access = Public; + } + else if (classDef->str() == "class") { type = SpaceInfo::Class; className = classDef->next()->str(); @@ -732,31 +744,48 @@ SymbolDatabase::SpaceInfo::SpaceInfo(SymbolDatabase *check_, const Token *classD nestedIn->nestedList.push_back(this); } +// Get variable list.. void SymbolDatabase::SpaceInfo::getVarList() { - // Get variable list.. - unsigned int indentlevel = 0; - AccessControl varaccess = type == Struct ? Public : Private; - for (const Token *tok = classStart; tok; tok = tok->next()) + AccessControl varaccess = type == Class ? Private : Public; + const Token *start; + + if (classStart) + start = classStart->next(); + else + start = check->_tokenizer->tokens(); + + for (const Token *tok = start; tok; tok = tok->next()) { - if (!tok->next()) + if (tok->str() == "}") break; - if (tok->str() == "{") - ++indentlevel; - else if (tok->str() == "}") + // Is it a function? + else if (tok->str() == "{") { - if (indentlevel <= 1) - break; - --indentlevel; + tok = tok->link(); + continue; } - if (indentlevel != 1) - continue; + // Is it a nested class or structure? + else if (Token::Match(tok, "class|struct|union|namespace %type% :|{")) + { + tok = tok->tokAt(2); + while (tok && tok->str() != "{") + tok = tok->next(); + if (tok) + { + // skip implementation + tok = tok->link(); + continue; + } + else + break; + } // Borland C++: Skip all variables in the __published section. // These are automaticly initialized. - if (tok->str() == "__published:") + else if (tok->str() == "__published:") { for (; tok; tok = tok->next()) { @@ -772,165 +801,177 @@ void SymbolDatabase::SpaceInfo::getVarList() } // "private:" "public:" "protected:" etc - bool b = false; - if (tok->str() == "public:") + else if (tok->str() == "public:") { varaccess = Public; - b = true; + continue; } else if (tok->str() == "protected:") { varaccess = Protected; - b = true; + continue; } else if (tok->str() == "private:") { varaccess = Private; - b = true; + continue; } - // 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% ;")) + else if (Token::Match(tok, "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") + else if (tok->str() == "__property") continue; + // Search for start of statement.. + else if (!tok->previous() || !Token::Match(tok->previous(), ";|{|}|public:|protected:|private:")) + continue; + + // This is the start of a statement + const Token *vartok = 0; + // Is it const..? bool isConst = false; - if (next->str() == "const") + if (tok->str() == "const") { - next = next->next(); + tok = tok->next(); isConst = true; } // Is it a static variable? - const bool isStatic(Token::simpleMatch(next, "static")); + const bool isStatic(Token::simpleMatch(tok, "static")); if (isStatic) { - next = next->next(); + tok = tok->next(); } // Is it a mutable variable? - const bool isMutable(Token::simpleMatch(next, "mutable")); + const bool isMutable(Token::simpleMatch(tok, "mutable")); if (isMutable) { - next = next->next(); + tok = tok->next(); } // Is it const..? - if (next->str() == "const") + if (tok->str() == "const") { - next = next->next(); + tok = tok->next(); isConst = true; } - // Is it a variable declaration? bool isClass = false; - if (Token::Match(next, "%type% %var% ;|:")) + + // Is it a variable declaration? + if (Token::Match(tok, "%type% %var% ;|:")) { - if (!next->isStandardType()) + if (!tok->isStandardType()) isClass = true; - vartok = next->tokAt(1); + vartok = tok->tokAt(1); + tok = vartok->next(); + } + else if (Token::Match(tok, "%type% :: %type% %var% ;")) + { + isClass = true; + vartok = tok->tokAt(3); + tok = vartok->next(); + } + else if (Token::Match(tok, "%type% :: %type% :: %type% %var% ;")) + { + isClass = true; + vartok = tok->tokAt(5); + tok = vartok->next(); } // Structure? - else if (Token::Match(next, "struct|union %type% %var% ;")) + else if (Token::Match(tok, "struct|union %type% %var% ;")) { - vartok = next->tokAt(2); + vartok = tok->tokAt(2); + tok = vartok->next(); } // 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); + else if (Token::Match(tok, "%type% * %var% ;")) + { + vartok = tok->tokAt(2); + tok = vartok->next(); + } + else if (Token::Match(tok, "%type% %type% * %var% ;")) + { + vartok = tok->tokAt(3); + tok = vartok->next(); + } + else if (Token::Match(tok, "%type% :: %type% * %var% ;")) + { + vartok = tok->tokAt(4); + tok = vartok->next(); + } + else if (Token::Match(tok, "%type% :: %type% :: %type% * %var% ;")) + { + vartok = tok->tokAt(6); + tok = vartok->next(); + } // Array? - else if (Token::Match(next, "%type% %var% [") && next->next()->str() != "operator") + else if (Token::Match(tok, "%type% %var% [") && tok->next()->str() != "operator") { - if (!next->isStandardType()) + if (!tok->isStandardType()) isClass = true; - vartok = next->tokAt(1); + vartok = tok->tokAt(1); + tok = vartok->next()->link()->next(); } // 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% ;")) + else if (Token::Match(tok, "%type% * %var% [")) { - isClass = true; - vartok = next->tokAt(3); + vartok = tok->tokAt(2); + tok = vartok->next(); } - else if (Token::Match(next, "%type% :: %type% :: %type% %var% ;")) + else if (Token::Match(tok, "%type% :: %type% * %var% [")) { - isClass = true; - vartok = next->tokAt(5); + vartok = tok->tokAt(4); + tok = vartok->next(); + } + else if (Token::Match(tok, "%type% :: %type% :: %type% * %var% [")) + { + vartok = tok->tokAt(6); + tok = vartok->next(); } // Container.. - else if (Token::Match(next, "%type% :: %type% <") || - Token::Match(next, "%type% <")) + else if (Token::Match(tok, "%type% :: %type% <") || + Token::Match(tok, "%type% <")) { // find matching ">" int level = 0; - for (; next; next = next->next()) + for (; tok; tok = tok->next()) { - if (next->str() == "<") + if (tok->str() == "<") level++; - else if (next->str() == ">") + else if (tok->str() == ">") { level--; if (level == 0) break; } } - if (next && Token::Match(next, "> %var% ;")) + if (tok && Token::Match(tok, "> %var% ;")) { isClass = true; - vartok = next->tokAt(1); + vartok = tok->tokAt(1); + tok = vartok->next(); + } + else if (tok && Token::Match(tok, "> * %var% ;")) + { + vartok = tok->tokAt(2); + tok = vartok->next(); } - 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.. diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index aaec68891..4cecb6105 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -147,7 +147,7 @@ public: class SpaceInfo { public: - enum SpaceType { Class, Struct, Union, Namespace, Function }; + enum SpaceType { Global, Class, Struct, Union, Namespace, Function }; SpaceInfo(SymbolDatabase *check_, const Token *classDef_, SpaceInfo *nestedIn_); @@ -166,6 +166,11 @@ public: AccessControl access; unsigned int numConstructors; + bool isClassOrStruct() const + { + return (type == Class || type == Struct); + } + /** * @brief find if name is in nested list * @param name name of nested space @@ -237,7 +242,6 @@ public: private: void addFunction(SpaceInfo **info, const Token **tok, const Token *argStart); void addNewFunction(SpaceInfo **info, const Token **tok); - void addIfFunction(SpaceInfo **info, const Token **tok); bool isFunction(const Token *tok, const Token **funcStart, const Token **argStart) const; bool argsMatch(const Token *first, const Token *second, const std::string &path, unsigned int depth) const;