Symbol database: better handling of 'friend'. ticket: #1895
This commit is contained in:
parent
cb72f21994
commit
c88aa242e8
|
@ -69,7 +69,7 @@ void CheckClass::createSymbolDatabase()
|
|||
new_info->nest = info;
|
||||
new_info->access = tok->str() == "struct" ? Public : Private;
|
||||
new_info->numConstructors = 0;
|
||||
new_info->varlist = getVarList(tok);
|
||||
new_info->getVarList();
|
||||
|
||||
// goto initial '{'
|
||||
const Token *tok2 = initBaseInfo(new_info, tok);
|
||||
|
@ -270,6 +270,18 @@ void CheckClass::createSymbolDatabase()
|
|||
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;
|
||||
|
||||
for (it = spaceInfoMMap.begin(); it != spaceInfoMMap.end(); ++it)
|
||||
{
|
||||
SpaceInfo *info = it->second;
|
||||
|
||||
// Delete the varlist..
|
||||
while (info->varlist)
|
||||
{
|
||||
Var *nextvar = info->varlist->next;
|
||||
delete info->varlist;
|
||||
info->varlist = nextvar;
|
||||
}
|
||||
|
||||
delete info;
|
||||
}
|
||||
delete it->second;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -374,10 +374,10 @@ const Token *CheckClass::initBaseInfo(SpaceInfo *info, const Token *tok)
|
|||
return tok2;
|
||||
}
|
||||
|
||||
CheckClass::Var *CheckClass::getVarList(const Token *tok1)
|
||||
void CheckClass::SpaceInfo::getVarList()
|
||||
{
|
||||
// Get variable list..
|
||||
Var *varlist = NULL;
|
||||
const Token *tok1 = classDef;
|
||||
unsigned int indentlevel = 0;
|
||||
bool isStruct = tok1->str() == "struct";
|
||||
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 (!varname.empty() && varname != "operator")
|
||||
{
|
||||
Var *var = new Var(varname, false, priv, isMutable, isStatic, isClass, varlist);
|
||||
varlist = var;
|
||||
varlist.push_back(Var(varname, false, priv, isMutable, isStatic, isClass));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
unsigned int indentlevel = 0;
|
||||
const Token *ftok = func.token;
|
||||
|
||||
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% ("))
|
||||
{
|
||||
initVar(varlist, ftok->strAt(0));
|
||||
initVar(ftok->strAt(0));
|
||||
|
||||
// assignment in the initializer..
|
||||
// : var(value = x)
|
||||
if (Token::Match(ftok->tokAt(2), "%var% ="))
|
||||
initVar(varlist, ftok->strAt(2));
|
||||
initVar(ftok->strAt(2));
|
||||
}
|
||||
|
||||
Assign |= (ftok->str() == ":");
|
||||
|
@ -608,7 +614,7 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
|
|||
// Variable getting value from stream?
|
||||
if (Token::Match(ftok, ">> %var%"))
|
||||
{
|
||||
initVar(varlist, ftok->strAt(1));
|
||||
initVar(ftok->strAt(1));
|
||||
}
|
||||
|
||||
// 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..
|
||||
if (Token::simpleMatch(ftok->next(), "* this = "))
|
||||
{
|
||||
for (Var *var = varlist; var; var = var->next)
|
||||
var->init = true;
|
||||
markAllVar(true);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -655,15 +660,14 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
|
|||
// Clearing all variables..
|
||||
if (Token::simpleMatch(ftok, "memset ( this ,"))
|
||||
{
|
||||
for (Var *var = varlist; var; var = var->next)
|
||||
var->init = true;
|
||||
markAllVar(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Clearing array..
|
||||
else if (Token::Match(ftok, "memset ( %var% ,"))
|
||||
{
|
||||
initVar(varlist, ftok->strAt(2));
|
||||
initVar(ftok->strAt(2));
|
||||
ftok = ftok->next()->link();
|
||||
continue;
|
||||
}
|
||||
|
@ -676,8 +680,7 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
|
|||
{
|
||||
if (tok2->str() == "this")
|
||||
{
|
||||
for (Var *var = varlist; var; var = var->next)
|
||||
var->init = true;
|
||||
markAllVar(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -686,64 +689,54 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
|
|||
// assume that all variables are initialized
|
||||
if (std::find(callstack.begin(), callstack.end(), ftok->str()) != callstack.end())
|
||||
{
|
||||
for (Var *var = varlist; var; var = var->next)
|
||||
var->init = true;
|
||||
markAllVar(true);
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
const Token *ftok2 = _tokenizer->findClassFunction(tok1, classname, ftok->strAt(0), i, isStruct);
|
||||
if (ftok2)
|
||||
// check if member function
|
||||
std::list<Func>::const_iterator it;
|
||||
for (it = functionList.begin(); it != functionList.end(); ++it)
|
||||
{
|
||||
callstack.push_back(ftok->str());
|
||||
initializeVarList(tok1, ftok2, varlist, callstack);
|
||||
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();
|
||||
if (ftok->str() == it->tokenDef->str())
|
||||
break;
|
||||
}
|
||||
|
||||
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();
|
||||
if (!tok)
|
||||
break;
|
||||
// initialize variable use list using member function
|
||||
callstack.push_back(ftok->str());
|
||||
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;
|
||||
}
|
||||
else if (tok->str() == ftok->str() || tok->str() == "friend")
|
||||
{
|
||||
if (tok->next()->str() == "(" || tok->str() == "friend")
|
||||
{
|
||||
tok = 0;
|
||||
break;
|
||||
markAllVar(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
// bail out..
|
||||
if (!tok || derived)
|
||||
|
||||
// not member function
|
||||
else
|
||||
{
|
||||
for (Var *var = varlist; var; var = var->next)
|
||||
var->init = true;
|
||||
break;
|
||||
}
|
||||
// could be a base class virtual function, so we assume it initializes everything
|
||||
if (!derivedFrom.empty())
|
||||
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.
|
||||
// assume all variables that are passed to it are initialized..
|
||||
else
|
||||
{
|
||||
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() == "(")
|
||||
++indentlevel2;
|
||||
|
@ -755,47 +748,47 @@ void CheckClass::initializeVarList(const Token *tok1, const Token *ftok, Var *va
|
|||
}
|
||||
if (tok->isName())
|
||||
{
|
||||
initVar(varlist, tok->strAt(0));
|
||||
initVar(tok->strAt(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Assignment of member variable?
|
||||
else if (Token::Match(ftok, "%var% ="))
|
||||
{
|
||||
initVar(varlist, ftok->strAt(0));
|
||||
initVar(ftok->strAt(0));
|
||||
}
|
||||
|
||||
// Assignment of array item of member variable?
|
||||
else if (Token::Match(ftok, "%var% [ %any% ] ="))
|
||||
{
|
||||
initVar(varlist, ftok->strAt(0));
|
||||
initVar(ftok->strAt(0));
|
||||
}
|
||||
|
||||
// Assignment of array item of member variable?
|
||||
else if (Token::Match(ftok, "%var% [ %any% ] [ %any% ] ="))
|
||||
{
|
||||
initVar(varlist, ftok->strAt(0));
|
||||
initVar(ftok->strAt(0));
|
||||
}
|
||||
|
||||
// Assignment of array item of member variable?
|
||||
else if (Token::Match(ftok, "* %var% ="))
|
||||
{
|
||||
initVar(varlist, ftok->strAt(1));
|
||||
initVar(ftok->strAt(1));
|
||||
}
|
||||
|
||||
// Assignment of struct member of member variable?
|
||||
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.
|
||||
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 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)
|
||||
{
|
||||
|
@ -928,14 +922,14 @@ void CheckClass::constructors()
|
|||
continue;
|
||||
|
||||
// Mark all variables not used
|
||||
for (Var *var = info->varlist; var; var = var->next)
|
||||
var->init = false;
|
||||
info->markAllVar(false);
|
||||
|
||||
std::list<std::string> callstack;
|
||||
initializeVarList(info->classDef, it->token, info->varlist, callstack);
|
||||
info->initializeVarList(*it, callstack);
|
||||
|
||||
// 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
|
||||
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() == "::")
|
||||
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())
|
||||
{
|
||||
|
|
|
@ -132,14 +132,13 @@ private:
|
|||
class Var
|
||||
{
|
||||
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_),
|
||||
init(init_),
|
||||
priv(priv_),
|
||||
isMutable(mutable_),
|
||||
isStatic(static_),
|
||||
isClass(class_),
|
||||
next(next_)
|
||||
isClass(class_)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -160,12 +159,6 @@ private:
|
|||
|
||||
/** @brief is this variable a class (or unknown type)? */
|
||||
bool isClass;
|
||||
|
||||
/** @brief next Var item */
|
||||
Var *next;
|
||||
|
||||
private:
|
||||
Var& operator=(const Var&); // disallow assignments
|
||||
};
|
||||
|
||||
struct Func
|
||||
|
@ -213,6 +206,12 @@ private:
|
|||
SpaceInfo *spaceInfo;
|
||||
};
|
||||
|
||||
struct FriendInfo
|
||||
{
|
||||
std::string name;
|
||||
SpaceInfo *spaceInfo;
|
||||
};
|
||||
|
||||
struct SpaceInfo
|
||||
{
|
||||
bool isNamespace;
|
||||
|
@ -222,10 +221,33 @@ private:
|
|||
const Token *classEnd; // '}' token
|
||||
unsigned int numConstructors;
|
||||
std::list<Func> functionList;
|
||||
Var *varlist;
|
||||
std::list<Var> varlist;
|
||||
std::vector<BaseInfo> derivedFrom;
|
||||
std::list<FriendInfo> friendList;
|
||||
SpaceInfo *nest;
|
||||
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 */
|
||||
|
@ -233,24 +255,6 @@ private:
|
|||
|
||||
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 checkConstFunc(const SpaceInfo *info, const Token *tok);
|
||||
|
||||
|
|
Loading…
Reference in New Issue