Improvement: Set varId for variables with global scope operator :: Refactorization: Moved internal class from tokenize.h to tokenize.cpp (#4184)

Merged from LCppC.
This commit is contained in:
PKEuS 2022-06-11 08:11:16 +02:00 committed by GitHub
parent c9b85010f9
commit 99ce89c003
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 147 additions and 114 deletions

View File

@ -3424,14 +3424,85 @@ void Tokenizer::simplifyTemplates()
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::string,int> &variableId, bool executableScope, bool cpp, bool c) /** Class used in Tokenizer::setVarIdPass1 */
class VariableMap {
private:
std::map<std::string, nonneg int> mVariableId;
std::map<std::string, nonneg int> mVariableId_global;
std::stack<std::vector<std::pair<std::string, nonneg int>>> mScopeInfo;
mutable nonneg int mVarId;
public:
VariableMap() : mVarId(0) {}
void enterScope();
bool leaveScope();
void addVariable(const std::string& varname, bool globalNamespace);
bool hasVariable(const std::string& varname) const {
return mVariableId.find(varname) != mVariableId.end();
}
std::map<std::string, nonneg int>::const_iterator find(const std::string& varname, bool global) const {
return map(global).find(varname);
}
std::map<std::string, nonneg int>::const_iterator end() const {
return mVariableId.end();
}
const std::map<std::string, nonneg int>& map(bool global) const {
return global ? mVariableId_global : mVariableId;
}
nonneg int* getVarId() const {
return &mVarId;
}
};
void VariableMap::enterScope()
{
mScopeInfo.push(std::vector<std::pair<std::string, nonneg int>>());
}
bool VariableMap::leaveScope()
{
if (mScopeInfo.empty())
return false;
for (const std::pair<std::string, nonneg int>& outerVariable : mScopeInfo.top()) {
if (outerVariable.second != 0)
mVariableId[outerVariable.first] = outerVariable.second;
else
mVariableId.erase(outerVariable.first);
}
mScopeInfo.pop();
return true;
}
void VariableMap::addVariable(const std::string& varname, bool globalNamespace)
{
if (mScopeInfo.empty()) {
mVariableId[varname] = ++mVarId;
if (globalNamespace)
mVariableId_global[varname] = mVariableId[varname];
return;
}
std::map<std::string, nonneg int>::iterator it = mVariableId.find(varname);
if (it == mVariableId.end()) {
mScopeInfo.top().push_back(std::pair<std::string, nonneg int>(varname, 0));
mVariableId[varname] = ++mVarId;
if (globalNamespace)
mVariableId_global[varname] = mVariableId[varname];
return;
}
mScopeInfo.top().push_back(std::pair<std::string, nonneg int>(varname, it->second));
it->second = ++mVarId;
}
static bool setVarIdParseDeclaration(const Token **tok, const VariableMap& variableMap, bool executableScope, bool cpp, bool c)
{ {
const Token *tok2 = *tok; const Token *tok2 = *tok;
if (!tok2->isName()) if (!tok2->isName())
return false; return false;
int typeCount = 0; nonneg int typeCount = 0;
int singleNameCount = 0; nonneg int singleNameCount = 0;
bool hasstruct = false; // Is there a "struct" or "class"? bool hasstruct = false; // Is there a "struct" or "class"?
bool bracket = false; bool bracket = false;
bool ref = false; bool ref = false;
@ -3450,7 +3521,7 @@ static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::stri
singleNameCount = 0; singleNameCount = 0;
} else if (Token::Match(tok2, "const|extern")) { } else if (Token::Match(tok2, "const|extern")) {
// just skip "const", "extern" // just skip "const", "extern"
} else if (!hasstruct && variableId.find(tok2->str()) != variableId.end() && tok2->previous()->str() != "::") { } else if (!hasstruct && variableMap.find(tok2->str(), false) != variableMap.end() && tok2->previous()->str() != "::") {
++typeCount; ++typeCount;
tok2 = tok2->next(); tok2 = tok2->next();
if (!tok2 || tok2->str() != "::") if (!tok2 || tok2->str() != "::")
@ -3554,17 +3625,17 @@ static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::stri
void Tokenizer::setVarIdStructMembers(Token **tok1, void Tokenizer::setVarIdStructMembers(Token **tok1,
std::map<int, std::map<std::string, int>>& structMembers, std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
nonneg int *varId) const nonneg int *varId) const
{ {
Token *tok = *tok1; Token *tok = *tok1;
if (Token::Match(tok, "%name% = { . %name% =|{")) { if (Token::Match(tok, "%name% = { . %name% =|{")) {
const int struct_varid = tok->varId(); const nonneg int struct_varid = tok->varId();
if (struct_varid == 0) if (struct_varid == 0)
return; return;
std::map<std::string, int>& members = structMembers[struct_varid]; std::map<std::string, nonneg int>& members = structMembers[struct_varid];
tok = tok->tokAt(3); tok = tok->tokAt(3);
while (tok->str() != "}") { while (tok->str() != "}") {
@ -3572,7 +3643,7 @@ void Tokenizer::setVarIdStructMembers(Token **tok1,
tok = tok->link(); tok = tok->link();
if (Token::Match(tok->previous(), "[,{] . %name% =|{")) { if (Token::Match(tok->previous(), "[,{] . %name% =|{")) {
tok = tok->next(); tok = tok->next();
const std::map<std::string, int>::iterator it = members.find(tok->str()); const std::map<std::string, nonneg int>::iterator it = members.find(tok->str());
if (it == members.end()) { if (it == members.end()) {
members[tok->str()] = ++(*varId); members[tok->str()] = ++(*varId);
tok->varId(*varId); tok->varId(*varId);
@ -3593,7 +3664,7 @@ void Tokenizer::setVarIdStructMembers(Token **tok1,
tok = tok->tokAt(3); tok = tok->tokAt(3);
continue; continue;
} }
const int struct_varid = tok->varId(); const nonneg int struct_varid = tok->varId();
tok = tok->tokAt(2); tok = tok->tokAt(2);
if (struct_varid == 0) if (struct_varid == 0)
continue; continue;
@ -3605,8 +3676,8 @@ void Tokenizer::setVarIdStructMembers(Token **tok1,
if (TemplateSimplifier::templateParameters(tok->next()) > 0) if (TemplateSimplifier::templateParameters(tok->next()) > 0)
break; break;
std::map<std::string, int>& members = structMembers[struct_varid]; std::map<std::string, nonneg int>& members = structMembers[struct_varid];
const std::map<std::string, int>::iterator it = members.find(tok->str()); const std::map<std::string, nonneg int>::iterator it = members.find(tok->str());
if (it == members.end()) { if (it == members.end()) {
members[tok->str()] = ++(*varId); members[tok->str()] = ++(*varId);
tok->varId(*varId); tok->varId(*varId);
@ -3622,7 +3693,7 @@ void Tokenizer::setVarIdStructMembers(Token **tok1,
void Tokenizer::setVarIdClassDeclaration(const Token * const startToken, void Tokenizer::setVarIdClassDeclaration(const Token * const startToken,
const VariableMap &variableMap, const VariableMap &variableMap,
const nonneg int scopeStartVarId, const nonneg int scopeStartVarId,
std::map<int, std::map<std::string,int>>& structMembers) std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers)
{ {
// end of scope // end of scope
const Token * const endToken = startToken->link(); const Token * const endToken = startToken->link();
@ -3663,7 +3734,7 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken,
--indentlevel; --indentlevel;
inEnum = false; inEnum = false;
} else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %name% [({]")) { } else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %name% [({]")) {
const std::map<std::string, int>::const_iterator it = variableMap.find(tok->str()); const std::map<std::string, nonneg int>::const_iterator it = variableMap.find(tok->str(), false);
if (it != variableMap.end()) { if (it != variableMap.end()) {
tok->varId(it->second); tok->varId(it->second);
} }
@ -3681,7 +3752,7 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken,
} }
if (!inEnum) { if (!inEnum) {
const std::map<std::string, int>::const_iterator it = variableMap.find(tok->str()); const std::map<std::string, nonneg int>::const_iterator it = variableMap.find(tok->str(), false);
if (it != variableMap.end()) { if (it != variableMap.end()) {
tok->varId(it->second); tok->varId(it->second);
setVarIdStructMembers(&tok, structMembers, variableMap.getVarId()); setVarIdStructMembers(&tok, structMembers, variableMap.getVarId());
@ -3700,8 +3771,8 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken,
void Tokenizer::setVarIdClassFunction(const std::string &classname, void Tokenizer::setVarIdClassFunction(const std::string &classname,
Token * const startToken, Token * const startToken,
const Token * const endToken, const Token * const endToken,
const std::map<std::string, int> &varlist, const std::map<std::string, nonneg int> &varlist,
std::map<int, std::map<std::string, int>>& structMembers, std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
nonneg int *varId_) nonneg int *varId_)
{ {
for (Token *tok2 = startToken; tok2 && tok2 != endToken; tok2 = tok2->next()) { for (Token *tok2 = startToken; tok2 && tok2 != endToken; tok2 = tok2->next()) {
@ -3716,7 +3787,7 @@ void Tokenizer::setVarIdClassFunction(const std::string &classname,
if (Token::Match(tok2, "%name% ::")) if (Token::Match(tok2, "%name% ::"))
continue; continue;
const std::map<std::string,int>::const_iterator it = varlist.find(tok2->str()); const std::map<std::string, nonneg int>::const_iterator it = varlist.find(tok2->str());
if (it != varlist.end()) { if (it != varlist.end()) {
tok2->varId(it->second); tok2->varId(it->second);
setVarIdStructMembers(&tok2, structMembers, varId_); setVarIdStructMembers(&tok2, structMembers, varId_);
@ -3755,7 +3826,7 @@ void Tokenizer::setVarIdPass1()
const std::unordered_set<std::string>& notstart = (isC()) ? notstart_c : notstart_cpp; const std::unordered_set<std::string>& notstart = (isC()) ? notstart_c : notstart_cpp;
VariableMap variableMap; VariableMap variableMap;
std::map<int, std::map<std::string, int>> structMembers; std::map<nonneg int, std::map<std::string, nonneg int>> structMembers;
std::stack<VarIdScopeInfo> scopeStack; std::stack<VarIdScopeInfo> scopeStack;
@ -3817,8 +3888,8 @@ void Tokenizer::setVarIdPass1()
const Token * const startToken = (tok->str() == "{") ? tok : tok->link(); const Token * const startToken = (tok->str() == "{") ? tok : tok->link();
// parse anonymous unions as part of the current scope // parse anonymous namespaces as part of the current scope
if (!Token::Match(startToken->previous(), "union|struct|enum {") && if (!Token::Match(startToken->previous(), "union|struct|enum|namespace {") &&
!(initlist && Token::Match(startToken->previous(), "%name%|>|>>") && Token::Match(startToken->link(), "} ,|{"))) { !(initlist && Token::Match(startToken->previous(), "%name%|>|>>") && Token::Match(startToken->link(), "} ,|{"))) {
if (tok->str() == "{") { if (tok->str() == "{") {
@ -3918,7 +3989,7 @@ void Tokenizer::setVarIdPass1()
Token::simpleMatch(tok2->link(), "] =")) { Token::simpleMatch(tok2->link(), "] =")) {
while (tok2 && tok2->str() != "]") { while (tok2 && tok2->str() != "]") {
if (Token::Match(tok2, "%name% [,]]")) if (Token::Match(tok2, "%name% [,]]"))
variableMap.addVariable(tok2->str()); variableMap.addVariable(tok2->str(), false);
tok2 = tok2->next(); tok2 = tok2->next();
} }
continue; continue;
@ -3926,7 +3997,7 @@ void Tokenizer::setVarIdPass1()
} }
try { /* Ticket #8151 */ try { /* Ticket #8151 */
decl = setVarIdParseDeclaration(&tok2, variableMap.map(), scopeStack.top().isExecutable, isCPP(), isC()); decl = setVarIdParseDeclaration(&tok2, variableMap, scopeStack.top().isExecutable, isCPP(), isC());
} catch (const Token * errTok) { } catch (const Token * errTok) {
syntaxError(errTok); syntaxError(errTok);
} }
@ -3935,7 +4006,7 @@ void Tokenizer::setVarIdPass1()
if (Token *declTypeTok = Token::findsimplematch(tok, "decltype (", tok2)) { if (Token *declTypeTok = Token::findsimplematch(tok, "decltype (", tok2)) {
for (Token *declTok = declTypeTok->linkAt(1); declTok != declTypeTok; declTok = declTok->previous()) { for (Token *declTok = declTypeTok->linkAt(1); declTok != declTypeTok; declTok = declTok->previous()) {
if (declTok->isName() && !Token::Match(declTok->previous(), "::|.") && variableMap.hasVariable(declTok->str())) if (declTok->isName() && !Token::Match(declTok->previous(), "::|.") && variableMap.hasVariable(declTok->str()))
declTok->varId(variableMap.find(declTok->str())->second); declTok->varId(variableMap.find(declTok->str(), false)->second);
} }
} }
} }
@ -3994,14 +4065,14 @@ void Tokenizer::setVarIdPass1()
decl = false; decl = false;
if (decl) { if (decl) {
variableMap.addVariable(prev2->str()); variableMap.addVariable(prev2->str(), scopeStack.size() <= 1);
if (Token::simpleMatch(tok->previous(), "for (") && Token::Match(prev2, "%name% [=,]")) { if (Token::simpleMatch(tok->previous(), "for (") && Token::Match(prev2, "%name% [=,]")) {
for (const Token *tok3 = prev2->next(); tok3 && tok3->str() != ";"; tok3 = tok3->next()) { for (const Token *tok3 = prev2->next(); tok3 && tok3->str() != ";"; tok3 = tok3->next()) {
if (Token::Match(tok3, "[([]")) if (Token::Match(tok3, "[([]"))
tok3 = tok3->link(); tok3 = tok3->link();
if (Token::Match(tok3, ", %name% [,=;]")) if (Token::Match(tok3, ", %name% [,=;]"))
variableMap.addVariable(tok3->next()->str()); variableMap.addVariable(tok3->next()->str(), false);
} }
} }
@ -4014,7 +4085,7 @@ void Tokenizer::setVarIdPass1()
while (tok != end) { while (tok != end) {
if (tok->isName() && !(Token::simpleMatch(tok->next(), "<") && if (tok->isName() && !(Token::simpleMatch(tok->next(), "<") &&
Token::Match(tok->tokAt(-1), ":: %name%"))) { Token::Match(tok->tokAt(-1), ":: %name%"))) {
const std::map<std::string, int>::const_iterator it = variableMap.find(tok->str()); const std::map<std::string, nonneg int>::const_iterator it = variableMap.find(tok->str(), false);
if (it != variableMap.end()) if (it != variableMap.end())
tok->varId(it->second); tok->varId(it->second);
} }
@ -4032,9 +4103,14 @@ void Tokenizer::setVarIdPass1()
if (Token::Match(tok->previous(), "struct|enum|union") || (isCPP() && tok->strAt(-1) == "class")) if (Token::Match(tok->previous(), "struct|enum|union") || (isCPP() && tok->strAt(-1) == "class"))
continue; continue;
bool globalNamespace = false;
if (!isC()) { if (!isC()) {
if (tok->previous() && tok->previous()->str() == "::") if (tok->previous() && tok->previous()->str() == "::") {
continue; if (Token::Match(tok->tokAt(-2), ")|]|%name%"))
continue;
else
globalNamespace = true;
}
if (tok->next() && tok->next()->str() == "::") if (tok->next() && tok->next()->str() == "::")
continue; continue;
if (Token::simpleMatch(tok->tokAt(-2), ":: template")) if (Token::simpleMatch(tok->tokAt(-2), ":: template"))
@ -4074,13 +4150,13 @@ void Tokenizer::setVarIdPass1()
} }
if (!scopeStack.top().isEnum || !(Token::Match(tok->previous(), "{|,") && Token::Match(tok->next(), ",|=|}"))) { if (!scopeStack.top().isEnum || !(Token::Match(tok->previous(), "{|,") && Token::Match(tok->next(), ",|=|}"))) {
const std::map<std::string, int>::const_iterator it = variableMap.find(tok->str()); const std::map<std::string, nonneg int>::const_iterator it = variableMap.find(tok->str(), globalNamespace);
if (it != variableMap.end()) { if (it != variableMap.map(globalNamespace).end()) {
tok->varId(it->second); tok->varId(it->second);
setVarIdStructMembers(&tok, structMembers, variableMap.getVarId()); setVarIdStructMembers(&tok, structMembers, variableMap.getVarId());
} }
} }
} else if (Token::Match(tok, "::|. %name%")) { } else if (Token::Match(tok, "::|. %name%") && Token::Match(tok->previous(), ")|]|>|%name%")) {
// Don't set varid after a :: or . token // Don't set varid after a :: or . token
tok = tok->next(); tok = tok->next();
} else if (tok->str() == ":" && Token::Match(tok->tokAt(-2), "class %type%")) { } else if (tok->str() == ":" && Token::Match(tok->tokAt(-2), "class %type%")) {
@ -4193,7 +4269,7 @@ static Token * matchMemberFunctionName(const Member &func, const std::list<Scope
void Tokenizer::setVarIdPass2() void Tokenizer::setVarIdPass2()
{ {
std::map<int, std::map<std::string, int>> structMembers; std::map<nonneg int, std::map<std::string, nonneg int>> structMembers;
// Member functions and variables in this source // Member functions and variables in this source
std::list<Member> allMemberFunctions; std::list<Member> allMemberFunctions;
@ -4225,15 +4301,18 @@ void Tokenizer::setVarIdPass2()
} }
Token* const tok1 = tok; Token* const tok1 = tok;
if (Token::Match(tok->previous(), "!!:: %name% :: ~| %name%")) if (Token::Match(tok, "%name% :: ~| %name%"))
tok = tok->next(); tok = tok->next();
else if (Token::Match(tok->previous(), "!!:: %name% <") && Token::Match(tok->next()->findClosingBracket(),"> :: ~| %name%")) else if (Token::Match(tok, "%name% <") && Token::Match(tok->next()->findClosingBracket(),"> :: ~| %name%"))
tok = tok->next()->findClosingBracket()->next(); tok = tok->next()->findClosingBracket()->next();
else if (usingnamespaces.empty() || tok->varId() || !tok->isName() || tok->isStandardType() || tok->tokType() == Token::eKeyword || tok->tokType() == Token::eBoolean || else if (usingnamespaces.empty() || tok->varId() || !tok->isName() || tok->isStandardType() || tok->tokType() == Token::eKeyword || tok->tokType() == Token::eBoolean ||
Token::Match(tok->previous(), ".|namespace|class|struct|&|&&|*|> %name%") || Token::Match(tok->previous(), "%type%| %name% ( %type%|)") || Token::Match(tok, "public:|private:|protected:") || Token::Match(tok->previous(), ".|namespace|class|struct|&|&&|*|> %name%") || Token::Match(tok->previous(), "%type%| %name% ( %type%|)") || Token::Match(tok, "public:|private:|protected:") ||
(!tok->next() && Token::Match(tok->previous(), "}|; %name%"))) (!tok->next() && Token::Match(tok->previous(), "}|; %name%")))
continue; continue;
if (tok->strAt(-1) == "::" && tok->tokAt(-2) && tok->tokAt(-2)->isName())
continue;
while (Token::Match(tok, ":: ~| %name%")) { while (Token::Match(tok, ":: ~| %name%")) {
tok = tok->next(); tok = tok->next();
if (tok->str() == "~") if (tok->str() == "~")
@ -4257,7 +4336,7 @@ void Tokenizer::setVarIdPass2()
std::list<ScopeInfo2> scopeInfo; std::list<ScopeInfo2> scopeInfo;
// class members.. // class members..
std::map<std::string, std::map<std::string, int>> varsByClass; std::map<std::string, std::map<std::string, nonneg int>> varsByClass;
for (Token *tok = list.front(); tok; tok = tok->next()) { for (Token *tok = list.front(); tok; tok = tok->next()) {
while (tok->str() == "}" && !scopeInfo.empty() && tok == scopeInfo.back().bodyEnd) while (tok->str() == "}" && !scopeInfo.empty() && tok == scopeInfo.back().bodyEnd)
scopeInfo.pop_back(); scopeInfo.pop_back();
@ -4288,7 +4367,7 @@ void Tokenizer::setVarIdPass2()
for (const Token *it : classnameTokens) for (const Token *it : classnameTokens)
classname += (classname.empty() ? "" : " :: ") + it->str(); classname += (classname.empty() ? "" : " :: ") + it->str();
std::map<std::string, int> &thisClassVars = varsByClass[scopeName2 + classname]; std::map<std::string, nonneg int> &thisClassVars = varsByClass[scopeName2 + classname];
while (Token::Match(tokStart, ":|::|,|%name%")) { while (Token::Match(tokStart, ":|::|,|%name%")) {
if (Token::Match(tokStart, "%name% <")) { if (Token::Match(tokStart, "%name% <")) {
tokStart = tokStart->next()->findClosingBracket(); tokStart = tokStart->next()->findClosingBracket();
@ -4314,7 +4393,7 @@ void Tokenizer::setVarIdPass2()
break; break;
scopeName3.erase(pos + 4); scopeName3.erase(pos + 4);
} }
const std::map<std::string, int>& baseClassVars = varsByClass[baseClassName]; const std::map<std::string, nonneg int>& baseClassVars = varsByClass[baseClassName];
thisClassVars.insert(baseClassVars.begin(), baseClassVars.end()); thisClassVars.insert(baseClassVars.begin(), baseClassVars.end());
} }
tokStart = tokStart->next(); tokStart = tokStart->next();
@ -4406,7 +4485,7 @@ void Tokenizer::setVarIdPass2()
break; break;
// set varid // set varid
const std::map<std::string, int>::const_iterator varpos = thisClassVars.find(tok3->str()); const std::map<std::string, nonneg int>::const_iterator varpos = thisClassVars.find(tok3->str());
if (varpos != thisClassVars.end()) if (varpos != thisClassVars.end())
tok3->varId(varpos->second); tok3->varId(varpos->second);
@ -12415,50 +12494,6 @@ void Tokenizer::simplifyNamespaceAliases()
} }
} }
Tokenizer::VariableMap::VariableMap() : mVarId(0) {}
void Tokenizer::VariableMap::enterScope()
{
mScopeInfo.push(std::list<std::pair<std::string, int>>());
}
bool Tokenizer::VariableMap::leaveScope()
{
if (mScopeInfo.empty())
return false;
for (const std::pair<std::string, int> &outerVariable : mScopeInfo.top()) {
if (outerVariable.second != 0)
mVariableId[outerVariable.first] = outerVariable.second;
else
mVariableId.erase(outerVariable.first);
}
mScopeInfo.pop();
return true;
}
void Tokenizer::VariableMap::addVariable(const std::string &varname)
{
if (mScopeInfo.empty()) {
mVariableId[varname] = ++mVarId;
return;
}
std::map<std::string, int>::iterator it = mVariableId.find(varname);
if (it == mVariableId.end()) {
mScopeInfo.top().push_back(std::pair<std::string, int>(varname, 0));
mVariableId[varname] = ++mVarId;
return;
}
mScopeInfo.top().push_back(std::pair<std::string, int>(varname, it->second));
it->second = ++mVarId;
}
bool Tokenizer::VariableMap::hasVariable(const std::string &varname) const
{
return mVariableId.find(varname) != mVariableId.end();
}
bool Tokenizer::hasIfdef(const Token *start, const Token *end) const bool Tokenizer::hasIfdef(const Token *start, const Token *end) const
{ {
if (!mPreprocessor) if (!mPreprocessor)

View File

@ -40,6 +40,7 @@ class Token;
class TemplateSimplifier; class TemplateSimplifier;
class ErrorLogger; class ErrorLogger;
class Preprocessor; class Preprocessor;
class VariableMap;
namespace simplecpp { namespace simplecpp {
class TokenList; class TokenList;
@ -59,33 +60,6 @@ class CPPCHECKLIB Tokenizer {
friend class TestSimplifyTemplate; friend class TestSimplifyTemplate;
friend class TemplateSimplifier; friend class TemplateSimplifier;
/** Class used in Tokenizer::setVarIdPass1 */
class VariableMap {
private:
std::map<std::string, int> mVariableId;
std::stack<std::list<std::pair<std::string,int>>> mScopeInfo;
mutable nonneg int mVarId;
public:
VariableMap();
void enterScope();
bool leaveScope();
void addVariable(const std::string &varname);
bool hasVariable(const std::string &varname) const;
std::map<std::string,int>::const_iterator find(const std::string &varname) const {
return mVariableId.find(varname);
}
std::map<std::string,int>::const_iterator end() const {
return mVariableId.end();
}
const std::map<std::string,int> &map() const {
return mVariableId;
}
nonneg int *getVarId() const {
return &mVarId;
}
};
public: public:
Tokenizer(); Tokenizer();
Tokenizer(const Settings * settings, ErrorLogger *errorLogger); Tokenizer(const Settings * settings, ErrorLogger *errorLogger);
@ -798,17 +772,17 @@ private:
void setVarIdClassDeclaration(const Token * const startToken, void setVarIdClassDeclaration(const Token * const startToken,
const VariableMap &variableMap, const VariableMap &variableMap,
const nonneg int scopeStartVarId, const nonneg int scopeStartVarId,
std::map<int, std::map<std::string,int>>& structMembers); std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers);
void setVarIdStructMembers(Token **tok1, void setVarIdStructMembers(Token **tok1,
std::map<int, std::map<std::string, int>>& structMembers, std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
nonneg int *varId) const; nonneg int *varId) const;
void setVarIdClassFunction(const std::string &classname, void setVarIdClassFunction(const std::string &classname,
Token * const startToken, Token * const startToken,
const Token * const endToken, const Token * const endToken,
const std::map<std::string,int> &varlist, const std::map<std::string, nonneg int> &varlist,
std::map<int, std::map<std::string,int>>& structMembers, std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
nonneg int *varId_); nonneg int *varId_);
/** /**

View File

@ -743,7 +743,7 @@ static void setTokenValue(Token* tok, ValueFlow::Value value, const Settings* se
if (parent->isUnaryOp("&")) { if (parent->isUnaryOp("&")) {
pvalue.indirect++; pvalue.indirect++;
setTokenValue(parent, pvalue, settings); setTokenValue(parent, pvalue, settings);
} else if (Token::Match(parent, ". %var%") && parent->astOperand1() == tok) { } else if (Token::Match(parent, ". %var%") && parent->astOperand1() == tok && parent->astOperand2()) {
if (parent->originalName() == "->" && pvalue.indirect > 0) if (parent->originalName() == "->" && pvalue.indirect > 0)
pvalue.indirect--; pvalue.indirect--;
setTokenValue(parent->astOperand2(), pvalue, settings); setTokenValue(parent->astOperand2(), pvalue, settings);

View File

@ -178,6 +178,7 @@ private:
TEST_CASE(varid_for_auto_cpp17); TEST_CASE(varid_for_auto_cpp17);
TEST_CASE(varid_not); // #9689 'not x' TEST_CASE(varid_not); // #9689 'not x'
TEST_CASE(varid_declInIfCondition); TEST_CASE(varid_declInIfCondition);
TEST_CASE(varid_globalScope);
TEST_CASE(varidclass1); TEST_CASE(varidclass1);
TEST_CASE(varidclass2); TEST_CASE(varidclass2);
@ -2859,6 +2860,29 @@ private:
"}")); "}"));
} }
void varid_globalScope() {
const char code1[] = "int a[5];\n"
"namespace Z { struct B { int a[5]; } b; }\n"
"void f() {\n"
" int a[5];\n"
" memset(a, 123, 5);\n"
" memset(::a, 123, 5);\n"
" memset(Z::b.a, 123, 5);\n"
" memset(::Z::b.a, 123, 5);\n"
"}";
const char exp1[] = "1: int a@1 [ 5 ] ;\n"
"2: namespace Z { struct B { int a@2 [ 5 ] ; } ; struct B b@3 ; }\n"
"3: void f ( ) {\n"
"4: int a@4 [ 5 ] ;\n"
"5: memset ( a@4 , 123 , 5 ) ;\n"
"6: memset ( :: a@1 , 123 , 5 ) ;\n"
"7: memset ( Z :: b@3 . a , 123 , 5 ) ;\n"
"8: memset ( :: Z :: b@3 . a , 123 , 5 ) ;\n"
"9: }\n";
ASSERT_EQUALS(exp1, tokenize(code1));
}
void varidclass1() { void varidclass1() {
const std::string actual = tokenize( const std::string actual = tokenize(
"class Fred\n" "class Fred\n"