Symbol database: better handling of 'friend'. ticket: #1895

This commit is contained in:
Robert Reif 2010-08-11 22:36:04 +02:00 committed by Daniel Marjamäki
parent cb72f21994
commit c88aa242e8
2 changed files with 133 additions and 134 deletions

View File

@ -69,7 +69,7 @@ void CheckClass::createSymbolDatabase()
new_info->nest = info; new_info->nest = info;
new_info->access = tok->str() == "struct" ? Public : Private; new_info->access = tok->str() == "struct" ? Public : Private;
new_info->numConstructors = 0; new_info->numConstructors = 0;
new_info->varlist = getVarList(tok); new_info->getVarList();
// goto initial '{' // goto initial '{'
const Token *tok2 = initBaseInfo(new_info, tok); const Token *tok2 = initBaseInfo(new_info, tok);
@ -270,6 +270,18 @@ void CheckClass::createSymbolDatabase()
tok = tok->link(); tok = tok->link();
} }
} }
// 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);
}
} }
} }
} }
@ -280,19 +292,7 @@ CheckClass::~CheckClass()
std::multimap<std::string, SpaceInfo *>::iterator it; std::multimap<std::string, SpaceInfo *>::iterator it;
for (it = spaceInfoMMap.begin(); it != spaceInfoMMap.end(); ++it) for (it = spaceInfoMMap.begin(); it != spaceInfoMMap.end(); ++it)
{ delete it->second;
SpaceInfo *info = it->second;
// Delete the varlist..
while (info->varlist)
{
Var *nextvar = info->varlist->next;
delete info->varlist;
info->varlist = nextvar;
}
delete info;
}
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -374,10 +374,10 @@ const Token *CheckClass::initBaseInfo(SpaceInfo *info, const Token *tok)
return tok2; return tok2;
} }
CheckClass::Var *CheckClass::getVarList(const Token *tok1) void CheckClass::SpaceInfo::getVarList()
{ {
// Get variable list.. // Get variable list..
Var *varlist = NULL; const Token *tok1 = classDef;
unsigned int indentlevel = 0; unsigned int indentlevel = 0;
bool isStruct = tok1->str() == "struct"; bool isStruct = tok1->str() == "struct";
bool priv = !isStruct; bool priv = !isStruct;
@ -536,35 +536,41 @@ CheckClass::Var *CheckClass::getVarList(const Token *tok1)
// If the varname was set in the if-blocks above, create a entry for this variable.. // If the varname was set in the if-blocks above, create a entry for this variable..
if (!varname.empty() && varname != "operator") if (!varname.empty() && varname != "operator")
{ varlist.push_back(Var(varname, false, priv, isMutable, isStatic, isClass));
Var *var = new Var(varname, false, priv, isMutable, isStatic, isClass, varlist);
varlist = var;
} }
} }
return varlist;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CheckClass::initVar(Var *varlist, const std::string &varname) void CheckClass::SpaceInfo::initVar(const std::string &varname)
{ {
for (Var *var = varlist; var; var = var->next) std::list<Var>::iterator i;
for (i = varlist.begin(); i != varlist.end(); ++i)
{ {
if (var->name == varname) if (i->name == varname)
{ {
var->init = true; i->init = true;
return; return;
} }
} }
} }
void CheckClass::SpaceInfo::markAllVar(bool value)
{
std::list<Var>::iterator i;
for (i = varlist.begin(); i != varlist.end(); ++i)
i->init = value;
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *varlist, std::list<std::string> &callstack) void CheckClass::SpaceInfo::initializeVarList(const Func &func, std::list<std::string> &callstack)
{ {
const std::string &classname = tok1->next()->str();
bool isStruct = tok1->str() == "struct";
bool Assign = false; bool Assign = false;
unsigned int indentlevel = 0; unsigned int indentlevel = 0;
const Token *ftok = func.token;
for (; ftok; ftok = ftok->next()) for (; ftok; ftok = ftok->next())
{ {
@ -577,12 +583,12 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
{ {
if (Assign && Token::Match(ftok, "%var% (")) if (Assign && Token::Match(ftok, "%var% ("))
{ {
initVar(varlist, ftok->strAt(0)); initVar(ftok->strAt(0));
// assignment in the initializer.. // assignment in the initializer..
// : var(value = x) // : var(value = x)
if (Token::Match(ftok->tokAt(2), "%var% =")) if (Token::Match(ftok->tokAt(2), "%var% ="))
initVar(varlist, ftok->strAt(2)); initVar(ftok->strAt(2));
} }
Assign |= (ftok->str() == ":"); Assign |= (ftok->str() == ":");
@ -608,7 +614,7 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
// Variable getting value from stream? // Variable getting value from stream?
if (Token::Match(ftok, ">> %var%")) if (Token::Match(ftok, ">> %var%"))
{ {
initVar(varlist, ftok->strAt(1)); initVar(ftok->strAt(1));
} }
// Before a new statement there is "[{};)=]" // Before a new statement there is "[{};)=]"
@ -621,8 +627,7 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
// Using the operator= function to initialize all variables.. // Using the operator= function to initialize all variables..
if (Token::simpleMatch(ftok->next(), "* this = ")) if (Token::simpleMatch(ftok->next(), "* this = "))
{ {
for (Var *var = varlist; var; var = var->next) markAllVar(true);
var->init = true;
break; break;
} }
@ -655,15 +660,14 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
// Clearing all variables.. // Clearing all variables..
if (Token::simpleMatch(ftok, "memset ( this ,")) if (Token::simpleMatch(ftok, "memset ( this ,"))
{ {
for (Var *var = varlist; var; var = var->next) markAllVar(true);
var->init = true;
return; return;
} }
// Clearing array.. // Clearing array..
else if (Token::Match(ftok, "memset ( %var% ,")) else if (Token::Match(ftok, "memset ( %var% ,"))
{ {
initVar(varlist, ftok->strAt(2)); initVar(ftok->strAt(2));
ftok = ftok->next()->link(); ftok = ftok->next()->link();
continue; continue;
} }
@ -676,8 +680,7 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
{ {
if (tok2->str() == "this") if (tok2->str() == "this")
{ {
for (Var *var = varlist; var; var = var->next) markAllVar(true);
var->init = true;
return; return;
} }
} }
@ -686,64 +689,54 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
// assume that all variables are initialized // assume that all variables are initialized
if (std::find(callstack.begin(), callstack.end(), ftok->str()) != callstack.end()) if (std::find(callstack.begin(), callstack.end(), ftok->str()) != callstack.end())
{ {
for (Var *var = varlist; var; var = var->next) markAllVar(true);
var->init = true;
return; return;
} }
int i = 0; // check if member function
const Token *ftok2 = _tokenizer->findClassFunction(tok1, classname, ftok->strAt(0), i, isStruct); std::list<Func>::const_iterator it;
if (ftok2) for (it = functionList.begin(); it != functionList.end(); ++it)
{ {
callstack.push_back(ftok->str()); if (ftok->str() == it->tokenDef->str())
initializeVarList(tok1, ftok2, varlist, callstack); break;
callstack.pop_back();
}
else // there is a called member function, but it is not defined where we can find it, so we assume it initializes everything
{
// check if the function is part of this class..
const Token *tok = Token::findmatch(_tokenizer->tokens(), (tok1->str() + " " + classname + " {|:").c_str());
bool derived = false;
while (tok && tok->str() != "{")
{
if (tok->str() == ":")
derived = true;
tok = tok->next();
} }
for (tok = tok ? tok->next() : 0; tok; tok = tok->next()) // member function found
if (it != functionList.end())
{ {
if (tok->str() == "{") // member function has implementation
if (it->hasBody)
{ {
tok = tok->link(); // initialize variable use list using member function
if (!tok) callstack.push_back(ftok->str());
break; initializeVarList(*it, callstack);
callstack.pop_back();
} }
else if (tok->str() == "}")
// there is a called member function, but it has no implementation, so we assume it initializes everything
else
{ {
break; markAllVar(true);
}
else if (tok->str() == ftok->str() || tok->str() == "friend")
{
if (tok->next()->str() == "(" || tok->str() == "friend")
{
tok = 0;
break;
} }
} }
}
// bail out.. // not member function
if (!tok || derived) else
{ {
for (Var *var = varlist; var; var = var->next) // could be a base class virtual function, so we assume it initializes everything
var->init = true; if (!derivedFrom.empty())
break; markAllVar(true);
}
// has friends, so we assume it initializes everything
if (!friendList.empty())
markAllVar(true);
// the function is external and it's neither friend nor inherited virtual function. // the function is external and it's neither friend nor inherited virtual function.
// assume all variables that are passed to it are initialized.. // assume all variables that are passed to it are initialized..
else
{
unsigned int indentlevel2 = 0; unsigned int indentlevel2 = 0;
for (tok = ftok->tokAt(2); tok; tok = tok->next()) for (const Token *tok = ftok->tokAt(2); tok; tok = tok->next())
{ {
if (tok->str() == "(") if (tok->str() == "(")
++indentlevel2; ++indentlevel2;
@ -755,47 +748,47 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
} }
if (tok->isName()) if (tok->isName())
{ {
initVar(varlist, tok->strAt(0)); initVar(tok->strAt(0));
}
} }
} }
continue;
} }
} }
// Assignment of member variable? // Assignment of member variable?
else if (Token::Match(ftok, "%var% =")) else if (Token::Match(ftok, "%var% ="))
{ {
initVar(varlist, ftok->strAt(0)); initVar(ftok->strAt(0));
} }
// Assignment of array item of member variable? // Assignment of array item of member variable?
else if (Token::Match(ftok, "%var% [ %any% ] =")) else if (Token::Match(ftok, "%var% [ %any% ] ="))
{ {
initVar(varlist, ftok->strAt(0)); initVar(ftok->strAt(0));
} }
// Assignment of array item of member variable? // Assignment of array item of member variable?
else if (Token::Match(ftok, "%var% [ %any% ] [ %any% ] =")) else if (Token::Match(ftok, "%var% [ %any% ] [ %any% ] ="))
{ {
initVar(varlist, ftok->strAt(0)); initVar(ftok->strAt(0));
} }
// Assignment of array item of member variable? // Assignment of array item of member variable?
else if (Token::Match(ftok, "* %var% =")) else if (Token::Match(ftok, "* %var% ="))
{ {
initVar(varlist, ftok->strAt(1)); initVar(ftok->strAt(1));
} }
// Assignment of struct member of member variable? // Assignment of struct member of member variable?
else if (Token::Match(ftok, "%var% . %any% =")) else if (Token::Match(ftok, "%var% . %any% ="))
{ {
initVar(varlist, ftok->strAt(0)); initVar(ftok->strAt(0));
} }
// The functions 'clear' and 'Clear' are supposed to initialize variable. // The functions 'clear' and 'Clear' are supposed to initialize variable.
if (Token::Match(ftok, "%var% . clear|Clear (")) if (Token::Match(ftok, "%var% . clear|Clear ("))
{ {
initVar(varlist, ftok->strAt(0)); initVar(ftok->strAt(0));
} }
} }
} }
@ -910,7 +903,8 @@ void CheckClass::constructors()
if (info->numConstructors == 0) if (info->numConstructors == 0)
{ {
// If there is a private variable, there should be a constructor.. // If there is a private variable, there should be a constructor..
for (const Var *var = info->varlist; var; var = var->next) std::list<Var>::const_iterator var;
for (var = info->varlist.begin(); var != info->varlist.end(); ++var)
{ {
if (var->priv && !var->isClass && !var->isStatic) if (var->priv && !var->isClass && !var->isStatic)
{ {
@ -928,14 +922,14 @@ void CheckClass::constructors()
continue; continue;
// Mark all variables not used // Mark all variables not used
for (Var *var = info->varlist; var; var = var->next) info->markAllVar(false);
var->init = false;
std::list<std::string> callstack; std::list<std::string> callstack;
initializeVarList(info->classDef, it->token, info->varlist, callstack); info->initializeVarList(*it, callstack);
// Check if any variables are uninitialized // Check if any variables are uninitialized
for (Var *var = info->varlist; var; var = var->next) std::list<Var>::const_iterator var;
for (var = info->varlist.begin(); var != info->varlist.end(); ++var)
{ {
// skip classes for regular constructor // skip classes for regular constructor
if (var->isClass && it->type == Func::Constructor) if (var->isClass && it->type == Func::Constructor)
@ -1868,7 +1862,8 @@ bool CheckClass::isMemberVar(const SpaceInfo *info, const Token *tok)
if (tok->str() == info->className && tok->next()->str() == "::") if (tok->str() == info->className && tok->next()->str() == "::")
tok = tok->tokAt(2); tok = tok->tokAt(2);
for (const Var *var = info->varlist; var; var = var->next) std::list<Var>::const_iterator var;
for (var = info->varlist.begin(); var != info->varlist.end(); ++var)
{ {
if (var->name == tok->str()) if (var->name == tok->str())
{ {

View File

@ -132,14 +132,13 @@ private:
class Var class Var
{ {
public: public:
Var(const std::string &name_, bool init_ = false, bool priv_ = false, bool mutable_ = false, bool static_ = false, bool class_ = false, Var *next_ = 0) Var(const std::string &name_, bool init_ = false, bool priv_ = false, bool mutable_ = false, bool static_ = false, bool class_ = false)
: name(name_), : name(name_),
init(init_), init(init_),
priv(priv_), priv(priv_),
isMutable(mutable_), isMutable(mutable_),
isStatic(static_), isStatic(static_),
isClass(class_), isClass(class_)
next(next_)
{ {
} }
@ -160,12 +159,6 @@ private:
/** @brief is this variable a class (or unknown type)? */ /** @brief is this variable a class (or unknown type)? */
bool isClass; bool isClass;
/** @brief next Var item */
Var *next;
private:
Var& operator=(const Var&); // disallow assignments
}; };
struct Func struct Func
@ -213,6 +206,12 @@ private:
SpaceInfo *spaceInfo; SpaceInfo *spaceInfo;
}; };
struct FriendInfo
{
std::string name;
SpaceInfo *spaceInfo;
};
struct SpaceInfo struct SpaceInfo
{ {
bool isNamespace; bool isNamespace;
@ -222,10 +221,33 @@ private:
const Token *classEnd; // '}' token const Token *classEnd; // '}' token
unsigned int numConstructors; unsigned int numConstructors;
std::list<Func> functionList; std::list<Func> functionList;
Var *varlist; std::list<Var> varlist;
std::vector<BaseInfo> derivedFrom; std::vector<BaseInfo> derivedFrom;
std::list<FriendInfo> friendList;
SpaceInfo *nest; SpaceInfo *nest;
AccessControl access; AccessControl access;
/**
* @brief initialize a variable in the varlist
* @param varname name of variable to mark initialized
*/
void initVar(const std::string &varname);
/**
* @brief mark all variables in list
* @param value state to mark all variables
*/
void markAllVar(bool value);
/** @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<std::string> &callstack);
}; };
/** @brief Information about all namespaces/classes/structrues */ /** @brief Information about all namespaces/classes/structrues */
@ -233,24 +255,6 @@ private:
bool argsMatch(const Token *first, const Token *second, const std::string &path, unsigned int depth) const; bool argsMatch(const Token *first, const Token *second, const std::string &path, unsigned int depth) const;
/**
* @brief parse a scope for a constructor or member function and set the "init" flags in the provided varlist
* @param tok1 pointer to class declaration
* @param ftok pointer to the function that should be checked
* @param varlist variable list (the "init" flag will be set in these variables)
* @param callstack the function doesn't look into recursive function calls.
*/
void initializeVarList(const Token *tok1, const Token *ftok, Var *varlist, std::list<std::string> &callstack);
/** @brief initialize a variable in the varlist */
void initVar(Var *varlist, const std::string &varname);
/**
* @brief get varlist from a class definition
* @param tok1 pointer to class definition
*/
Var *getVarList(const Token *tok1);
bool isMemberVar(const SpaceInfo *info, const Token *tok); bool isMemberVar(const SpaceInfo *info, const Token *tok);
bool checkConstFunc(const SpaceInfo *info, const Token *tok); bool checkConstFunc(const SpaceInfo *info, const Token *tok);