diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp
new file mode 100644
index 000000000..71c18d1f0
--- /dev/null
+++ b/lib/symboldatabase.cpp
@@ -0,0 +1,1552 @@
+/*
+ * Cppcheck - A tool for static C/C++ code analysis
+ * Copyright (C) 2007-2010 Daniel Marjamäki and Cppcheck team.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+//---------------------------------------------------------------------------
+#include "symboldatabase.h"
+
+#include "tokenize.h"
+#include "token.h"
+#include "settings.h"
+#include "errorlogger.h"
+#include "check.h"
+
+#include
+
+#include
+#include
+#include
+#include
+
+
+//---------------------------------------------------------------------------
+
+SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
+ : _tokenizer(tokenizer), _settings(settings), _errorLogger(errorLogger)
+{
+ // 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();
+ }
+}
+
+SymbolDatabase::~SymbolDatabase()
+{
+ std::list::iterator it;
+
+ for (it = spaceInfoList.begin(); it != spaceInfoList.end(); ++it)
+ delete *it;
+}
+
+bool SymbolDatabase::isFunction(const Token *tok, const Token **funcStart, const Token **argStart) const
+{
+ // 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;
+}
+
+bool SymbolDatabase::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;
+}
+
+void SymbolDatabase::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 SymbolDatabase::addNewFunction(SymbolDatabase::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 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 '{'
+ 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;
+}
+//---------------------------------------------------------------------------
+
+SymbolDatabase::SpaceInfo::SpaceInfo(SymbolDatabase *check_, const Token *classDef_, SymbolDatabase::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 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())
+ {
+ 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)
+ {
+ std::list locationList;
+ ErrorLogger::ErrorMessage::FileLocation loc;
+ loc.line = vartok->linenr();
+ loc.setfile(check->_tokenizer->file(vartok));
+ locationList.push_back(loc);
+
+ const ErrorLogger::ErrorMessage errmsg(locationList,
+ Severity::debug,
+ "SymbolDatabase::SpaceInfo::getVarList found variable \'" + vartok->str() + "\' with varid 0.",
+ "debug");
+ if (check->_errorLogger)
+ check->_errorLogger->reportErr(errmsg);
+ else
+ Check::reportError(errmsg);
+ }
+
+ addVar(vartok, varaccess, isMutable, isStatic, isClass);
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+
+SymbolDatabase::SpaceInfo * SymbolDatabase::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;
+}
+
+//---------------------------------------------------------------------------
+
+const SymbolDatabase::Func *SymbolDatabase::SpaceInfo::getDestructor() const
+{
+ std::list::const_iterator it;
+ for (it = functionList.begin(); it != functionList.end(); ++it)
+ {
+ if (it->type == Func::Destructor)
+ return &*it;
+ }
+ return 0;
+}
+
+//---------------------------------------------------------------------------
+
+unsigned int SymbolDatabase::SpaceInfo::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;
+}
+
+//---------------------------------------------------------------------------
+
+void SymbolDatabase::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 SymbolDatabase::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 SymbolDatabase::SpaceInfo::assignAllVar()
+{
+ std::list::iterator i;
+
+ for (i = varlist.begin(); i != varlist.end(); ++i)
+ i->assign = true;
+}
+
+void SymbolDatabase::SpaceInfo::clearAllVar()
+{
+ std::list::iterator i;
+
+ for (i = varlist.begin(); i != varlist.end(); ++i)
+ {
+ i->assign = false;
+ i->init = false;
+ }
+}
+
+//---------------------------------------------------------------------------
+
+bool SymbolDatabase::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 SymbolDatabase::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 SymbolDatabase::isMemberVar(const SymbolDatabase::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 SymbolDatabase::isConstMemberFunc(const SymbolDatabase::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 SymbolDatabase::SpaceInfo *spaceInfo = info->derivedFrom[i].spaceInfo;
+
+ // find the function in the base class
+ if (spaceInfo)
+ {
+ if (isConstMemberFunc(spaceInfo, tok))
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool SymbolDatabase::checkConstFunc(const SymbolDatabase::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;
+}
+
+//---------------------------------------------------------------------------
+
+// check if this function is defined virtual in the base classes
+bool SymbolDatabase::isVirtualFunc(const SymbolDatabase::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 SymbolDatabase::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 (isVirtualFunc(derivedFrom, functionToken))
+ return true;
+ }
+ }
+ else
+ {
+ // unable to find base class so assume it has a virtual function
+ return true;
+ }
+ }
+
+ return false;
+}
+
diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h
new file mode 100644
index 000000000..f01b2ba50
--- /dev/null
+++ b/lib/symboldatabase.h
@@ -0,0 +1,247 @@
+/*
+ * Cppcheck - A tool for static C/C++ code analysis
+ * Copyright (C) 2007-2010 Daniel Marjamäki and Cppcheck team.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+//---------------------------------------------------------------------------
+#ifndef SymbolDatabaseH
+#define SymbolDatabaseH
+//---------------------------------------------------------------------------
+
+#include
+#include
+#include
+
+class Token;
+class Tokenizer;
+class Settings;
+class ErrorLogger;
+
+class SymbolDatabase
+{
+public:
+ /**
+ * @brief Access control.
+ */
+ enum AccessControl { Public, Protected, Private };
+
+ SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger);
+ ~SymbolDatabase();
+
+ /** @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(SymbolDatabase *check_, const Token *classDef_, SpaceInfo *nestedIn_);
+
+ SymbolDatabase *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);
+
+ /**
+ * @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;
+
+ /**
+ * @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;
+
+ bool isBaseClassFunc(const Token *tok);
+ };
+
+ 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 isVirtualFunc(const SymbolDatabase::SpaceInfo *info, const Token *functionToken) const;
+
+ /** @brief Information about all namespaces/classes/structrues */
+ std::list spaceInfoList;
+
+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;
+
+ const Tokenizer *_tokenizer;
+ const Settings *_settings;
+ ErrorLogger *_errorLogger;
+};
+
+#endif
+