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;
if (!tok2->isName())
return false;
int typeCount = 0;
int singleNameCount = 0;
nonneg int typeCount = 0;
nonneg int singleNameCount = 0;
bool hasstruct = false; // Is there a "struct" or "class"?
bool bracket = false;
bool ref = false;
@ -3450,7 +3521,7 @@ static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::stri
singleNameCount = 0;
} else if (Token::Match(tok2, "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;
tok2 = tok2->next();
if (!tok2 || tok2->str() != "::")
@ -3554,17 +3625,17 @@ static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::stri
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
{
Token *tok = *tok1;
if (Token::Match(tok, "%name% = { . %name% =|{")) {
const int struct_varid = tok->varId();
const nonneg int struct_varid = tok->varId();
if (struct_varid == 0)
return;
std::map<std::string, int>& members = structMembers[struct_varid];
std::map<std::string, nonneg int>& members = structMembers[struct_varid];
tok = tok->tokAt(3);
while (tok->str() != "}") {
@ -3572,7 +3643,7 @@ void Tokenizer::setVarIdStructMembers(Token **tok1,
tok = tok->link();
if (Token::Match(tok->previous(), "[,{] . %name% =|{")) {
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()) {
members[tok->str()] = ++(*varId);
tok->varId(*varId);
@ -3593,7 +3664,7 @@ void Tokenizer::setVarIdStructMembers(Token **tok1,
tok = tok->tokAt(3);
continue;
}
const int struct_varid = tok->varId();
const nonneg int struct_varid = tok->varId();
tok = tok->tokAt(2);
if (struct_varid == 0)
continue;
@ -3605,8 +3676,8 @@ void Tokenizer::setVarIdStructMembers(Token **tok1,
if (TemplateSimplifier::templateParameters(tok->next()) > 0)
break;
std::map<std::string, int>& members = structMembers[struct_varid];
const std::map<std::string, int>::iterator it = members.find(tok->str());
std::map<std::string, nonneg int>& members = structMembers[struct_varid];
const std::map<std::string, nonneg int>::iterator it = members.find(tok->str());
if (it == members.end()) {
members[tok->str()] = ++(*varId);
tok->varId(*varId);
@ -3622,7 +3693,7 @@ void Tokenizer::setVarIdStructMembers(Token **tok1,
void Tokenizer::setVarIdClassDeclaration(const Token * const startToken,
const VariableMap &variableMap,
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
const Token * const endToken = startToken->link();
@ -3663,7 +3734,7 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken,
--indentlevel;
inEnum = false;
} 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()) {
tok->varId(it->second);
}
@ -3681,7 +3752,7 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken,
}
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()) {
tok->varId(it->second);
setVarIdStructMembers(&tok, structMembers, variableMap.getVarId());
@ -3700,8 +3771,8 @@ void Tokenizer::setVarIdClassDeclaration(const Token * const startToken,
void Tokenizer::setVarIdClassFunction(const std::string &classname,
Token * const startToken,
const Token * const endToken,
const std::map<std::string, int> &varlist,
std::map<int, std::map<std::string, int>>& structMembers,
const std::map<std::string, nonneg int> &varlist,
std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
nonneg int *varId_)
{
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% ::"))
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()) {
tok2->varId(it->second);
setVarIdStructMembers(&tok2, structMembers, varId_);
@ -3755,7 +3826,7 @@ void Tokenizer::setVarIdPass1()
const std::unordered_set<std::string>& notstart = (isC()) ? notstart_c : notstart_cpp;
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;
@ -3817,8 +3888,8 @@ void Tokenizer::setVarIdPass1()
const Token * const startToken = (tok->str() == "{") ? tok : tok->link();
// parse anonymous unions as part of the current scope
if (!Token::Match(startToken->previous(), "union|struct|enum {") &&
// parse anonymous namespaces as part of the current scope
if (!Token::Match(startToken->previous(), "union|struct|enum|namespace {") &&
!(initlist && Token::Match(startToken->previous(), "%name%|>|>>") && Token::Match(startToken->link(), "} ,|{"))) {
if (tok->str() == "{") {
@ -3918,7 +3989,7 @@ void Tokenizer::setVarIdPass1()
Token::simpleMatch(tok2->link(), "] =")) {
while (tok2 && tok2->str() != "]") {
if (Token::Match(tok2, "%name% [,]]"))
variableMap.addVariable(tok2->str());
variableMap.addVariable(tok2->str(), false);
tok2 = tok2->next();
}
continue;
@ -3926,7 +3997,7 @@ void Tokenizer::setVarIdPass1()
}
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) {
syntaxError(errTok);
}
@ -3935,7 +4006,7 @@ void Tokenizer::setVarIdPass1()
if (Token *declTypeTok = Token::findsimplematch(tok, "decltype (", tok2)) {
for (Token *declTok = declTypeTok->linkAt(1); declTok != declTypeTok; declTok = declTok->previous()) {
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;
if (decl) {
variableMap.addVariable(prev2->str());
variableMap.addVariable(prev2->str(), scopeStack.size() <= 1);
if (Token::simpleMatch(tok->previous(), "for (") && Token::Match(prev2, "%name% [=,]")) {
for (const Token *tok3 = prev2->next(); tok3 && tok3->str() != ";"; tok3 = tok3->next()) {
if (Token::Match(tok3, "[([]"))
tok3 = tok3->link();
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) {
if (tok->isName() && !(Token::simpleMatch(tok->next(), "<") &&
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())
tok->varId(it->second);
}
@ -4032,9 +4103,14 @@ void Tokenizer::setVarIdPass1()
if (Token::Match(tok->previous(), "struct|enum|union") || (isCPP() && tok->strAt(-1) == "class"))
continue;
bool globalNamespace = false;
if (!isC()) {
if (tok->previous() && tok->previous()->str() == "::")
continue;
if (tok->previous() && tok->previous()->str() == "::") {
if (Token::Match(tok->tokAt(-2), ")|]|%name%"))
continue;
else
globalNamespace = true;
}
if (tok->next() && tok->next()->str() == "::")
continue;
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(), ",|=|}"))) {
const std::map<std::string, int>::const_iterator it = variableMap.find(tok->str());
if (it != variableMap.end()) {
const std::map<std::string, nonneg int>::const_iterator it = variableMap.find(tok->str(), globalNamespace);
if (it != variableMap.map(globalNamespace).end()) {
tok->varId(it->second);
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
tok = tok->next();
} 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()
{
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
std::list<Member> allMemberFunctions;
@ -4225,15 +4301,18 @@ void Tokenizer::setVarIdPass2()
}
Token* const tok1 = tok;
if (Token::Match(tok->previous(), "!!:: %name% :: ~| %name%"))
if (Token::Match(tok, "%name% :: ~| %name%"))
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();
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:") ||
(!tok->next() && Token::Match(tok->previous(), "}|; %name%")))
continue;
if (tok->strAt(-1) == "::" && tok->tokAt(-2) && tok->tokAt(-2)->isName())
continue;
while (Token::Match(tok, ":: ~| %name%")) {
tok = tok->next();
if (tok->str() == "~")
@ -4257,7 +4336,7 @@ void Tokenizer::setVarIdPass2()
std::list<ScopeInfo2> scopeInfo;
// 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()) {
while (tok->str() == "}" && !scopeInfo.empty() && tok == scopeInfo.back().bodyEnd)
scopeInfo.pop_back();
@ -4288,7 +4367,7 @@ void Tokenizer::setVarIdPass2()
for (const Token *it : classnameTokens)
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%")) {
if (Token::Match(tokStart, "%name% <")) {
tokStart = tokStart->next()->findClosingBracket();
@ -4314,7 +4393,7 @@ void Tokenizer::setVarIdPass2()
break;
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());
}
tokStart = tokStart->next();
@ -4406,7 +4485,7 @@ void Tokenizer::setVarIdPass2()
break;
// 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())
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
{
if (!mPreprocessor)

View File

@ -40,6 +40,7 @@ class Token;
class TemplateSimplifier;
class ErrorLogger;
class Preprocessor;
class VariableMap;
namespace simplecpp {
class TokenList;
@ -59,33 +60,6 @@ class CPPCHECKLIB Tokenizer {
friend class TestSimplifyTemplate;
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:
Tokenizer();
Tokenizer(const Settings * settings, ErrorLogger *errorLogger);
@ -798,17 +772,17 @@ private:
void setVarIdClassDeclaration(const Token * const startToken,
const VariableMap &variableMap,
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,
std::map<int, std::map<std::string, int>>& structMembers,
std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
nonneg int *varId) const;
void setVarIdClassFunction(const std::string &classname,
Token * const startToken,
const Token * const endToken,
const std::map<std::string,int> &varlist,
std::map<int, std::map<std::string,int>>& structMembers,
const std::map<std::string, nonneg int> &varlist,
std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
nonneg int *varId_);
/**

View File

@ -743,7 +743,7 @@ static void setTokenValue(Token* tok, ValueFlow::Value value, const Settings* se
if (parent->isUnaryOp("&")) {
pvalue.indirect++;
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)
pvalue.indirect--;
setTokenValue(parent->astOperand2(), pvalue, settings);

View File

@ -178,6 +178,7 @@ private:
TEST_CASE(varid_for_auto_cpp17);
TEST_CASE(varid_not); // #9689 'not x'
TEST_CASE(varid_declInIfCondition);
TEST_CASE(varid_globalScope);
TEST_CASE(varidclass1);
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() {
const std::string actual = tokenize(
"class Fred\n"