Fixed #7000 (Invalid varid - matching class with same name from other namespace)
This commit is contained in:
parent
74c778c5f0
commit
26b9e1528c
124
lib/tokenize.cpp
124
lib/tokenize.cpp
|
@ -2858,15 +2858,82 @@ void Tokenizer::setVarIdPass1()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct Member {
|
||||||
|
Member(const std::list<std::string> &s, Token *t) : scope(s), tok(t) {}
|
||||||
|
std::list<std::string> scope;
|
||||||
|
Token *tok;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ScopeInfo2 {
|
||||||
|
ScopeInfo2(const std::string &name_, const Token *classEnd_) : name(name_), classEnd(classEnd_) {}
|
||||||
|
const std::string name;
|
||||||
|
const Token * const classEnd;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getScopeName(const std::list<ScopeInfo2> &scopeInfo)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
for (std::list<ScopeInfo2>::const_iterator it = scopeInfo.begin(); it != scopeInfo.end(); ++it)
|
||||||
|
ret += (ret.empty() ? "" : " :: ") + (it->name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Token * matchFunctionName(const Member &func, const std::list<ScopeInfo2> &scopeInfo)
|
||||||
|
{
|
||||||
|
if (scopeInfo.empty())
|
||||||
|
return nullptr;
|
||||||
|
std::list<std::string>::const_iterator funcScopeIt = func.scope.begin();
|
||||||
|
Token *tok2 = func.tok;
|
||||||
|
for (std::list<ScopeInfo2>::const_iterator it = scopeInfo.begin(); tok2 && it != scopeInfo.end(); ++it) {
|
||||||
|
if (funcScopeIt != func.scope.end()) {
|
||||||
|
if (it->name != *funcScopeIt)
|
||||||
|
return nullptr;
|
||||||
|
funcScopeIt++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Token::Match(tok2, "%name% ::|<"))
|
||||||
|
return nullptr;
|
||||||
|
if (tok2->str() != it->name)
|
||||||
|
return nullptr;
|
||||||
|
if (tok2->next()->str() == "<") {
|
||||||
|
tok2 = tok2->next()->findClosingBracket();
|
||||||
|
if (!Token::simpleMatch(tok2, "> ::"))
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
tok2 = tok2->tokAt(2);
|
||||||
|
}
|
||||||
|
return (funcScopeIt == func.scope.end() && Token::Match(tok2, "~| %name% (")) ? tok2 : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void Tokenizer::setVarIdPass2()
|
void Tokenizer::setVarIdPass2()
|
||||||
{
|
{
|
||||||
std::map<unsigned int, std::map<std::string, unsigned int> > structMembers;
|
std::map<unsigned int, std::map<std::string, unsigned int> > structMembers;
|
||||||
|
|
||||||
// Member functions and variables in this source
|
// Member functions and variables in this source
|
||||||
std::list<Token *> allMemberFunctions;
|
std::list<Member> allMemberFunctions;
|
||||||
std::list<Token *> allMemberVars;
|
std::list<Member> allMemberVars;
|
||||||
if (!isC()) {
|
if (!isC()) {
|
||||||
|
std::map<const Token *, std::string> endOfScope;
|
||||||
|
std::list<std::string> scope;
|
||||||
for (Token *tok2 = list.front(); tok2; tok2 = tok2->next()) {
|
for (Token *tok2 = list.front(); tok2; tok2 = tok2->next()) {
|
||||||
|
if (!tok2->previous() || Token::Match(tok2->previous(), "[;{}]")) {
|
||||||
|
if (Token::Match(tok2, "using namespace %name% ;"))
|
||||||
|
scope.push_back(tok2->strAt(2));
|
||||||
|
else if (Token::Match(tok2, "namespace %name% {")) {
|
||||||
|
scope.push_back(tok2->strAt(1));
|
||||||
|
endOfScope[tok2->linkAt(2)] = tok2->strAt(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tok2->str() == "}") {
|
||||||
|
std::map<const Token *, std::string>::iterator it = endOfScope.find(tok2);
|
||||||
|
if (it != endOfScope.end())
|
||||||
|
scope.remove(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
const Token* tok3 = nullptr;
|
const Token* tok3 = nullptr;
|
||||||
if (Token::Match(tok2, "%name% :: ~| %name%"))
|
if (Token::Match(tok2, "%name% :: ~| %name%"))
|
||||||
tok3 = tok2->next();
|
tok3 = tok2->next();
|
||||||
|
@ -2885,28 +2952,41 @@ void Tokenizer::setVarIdPass2()
|
||||||
syntaxError(tok2);
|
syntaxError(tok2);
|
||||||
const std::string& str3 = tok3->str();
|
const std::string& str3 = tok3->str();
|
||||||
if (str3 == "(")
|
if (str3 == "(")
|
||||||
allMemberFunctions.push_back(tok2);
|
allMemberFunctions.push_back(Member(scope, tok2));
|
||||||
else if (str3 != "::" && tok2->strAt(-1) != "::") // Support only one depth
|
else if (str3 != "::" && tok2->strAt(-1) != "::") // Support only one depth
|
||||||
allMemberVars.push_back(tok2);
|
allMemberVars.push_back(Member(scope, tok2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::list<ScopeInfo2> scopeInfo;
|
||||||
|
|
||||||
// class members..
|
// class members..
|
||||||
std::map<std::string, std::map<std::string, unsigned int> > varsByClass;
|
std::map<std::string, std::map<std::string, unsigned 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().classEnd)
|
||||||
|
scopeInfo.pop_back();
|
||||||
|
|
||||||
if (!Token::Match(tok, "namespace|class|struct %name% {|:|::"))
|
if (!Token::Match(tok, "namespace|class|struct %name% {|:|::"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::string classname(tok->next()->str());
|
const std::string &scopeName(getScopeName(scopeInfo));
|
||||||
|
const std::string scopeName2(scopeName.empty() ? std::string() : (scopeName + " :: "));
|
||||||
|
|
||||||
|
std::list<const Token *> classnameTokens;
|
||||||
|
classnameTokens.push_back(tok->next());
|
||||||
const Token* tokStart = tok->tokAt(2);
|
const Token* tokStart = tok->tokAt(2);
|
||||||
unsigned int nestedCount = 1;
|
unsigned int nestedCount = 1;
|
||||||
while (Token::Match(tokStart, ":: %name%")) {
|
while (Token::Match(tokStart, ":: %name%")) {
|
||||||
classname += " :: " + tokStart->strAt(1);
|
classnameTokens.push_back(tokStart->next());
|
||||||
tokStart = tokStart->tokAt(2);
|
tokStart = tokStart->tokAt(2);
|
||||||
nestedCount++;
|
nestedCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, unsigned int>& thisClassVars = varsByClass[classname];
|
std::string classname;
|
||||||
|
for (std::list<const Token *>::const_iterator it = classnameTokens.begin(); it != classnameTokens.end(); ++it)
|
||||||
|
classname += (classname.empty() ? "" : " :: ") + (*it)->str();
|
||||||
|
|
||||||
|
std::map<std::string, unsigned int>& thisClassVars = varsByClass[scopeName2 + classname];
|
||||||
while (tokStart && tokStart->str() != "{") {
|
while (tokStart && tokStart->str() != "{") {
|
||||||
if (Token::Match(tokStart, "public|private|protected %name%"))
|
if (Token::Match(tokStart, "public|private|protected %name%"))
|
||||||
tokStart = tokStart->next();
|
tokStart = tokStart->next();
|
||||||
|
@ -2916,14 +2996,18 @@ void Tokenizer::setVarIdPass2()
|
||||||
}
|
}
|
||||||
tokStart = tokStart->next();
|
tokStart = tokStart->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// What member variables are there in this class?
|
// What member variables are there in this class?
|
||||||
if (tokStart) {
|
if (tokStart) {
|
||||||
|
for (std::list<const Token *>::const_iterator it = classnameTokens.begin(); it != classnameTokens.end(); ++it)
|
||||||
|
scopeInfo.push_back(ScopeInfo2((*it)->str(), tokStart->link()));
|
||||||
|
|
||||||
for (Token *tok2 = tokStart->next(); tok2 && tok2 != tokStart->link(); tok2 = tok2->next()) {
|
for (Token *tok2 = tokStart->next(); tok2 && tok2 != tokStart->link(); tok2 = tok2->next()) {
|
||||||
// skip parentheses..
|
// skip parentheses..
|
||||||
if (tok2->link()) {
|
if (tok2->link()) {
|
||||||
if (tok2->str() == "{") {
|
if (tok2->str() == "{") {
|
||||||
if (tok2->strAt(-1) == ")" || tok2->strAt(-2) == ")")
|
if (tok2->strAt(-1) == ")" || tok2->strAt(-2) == ")")
|
||||||
setVarIdClassFunction(classname, tok2, tok2->link(), thisClassVars, structMembers, &_varId);
|
setVarIdClassFunction(scopeName2 + classname, tok2, tok2->link(), thisClassVars, structMembers, &_varId);
|
||||||
tok2 = tok2->link();
|
tok2 = tok2->link();
|
||||||
} else if (tok2->str() == "(" && tok2->link()->strAt(1) != "(")
|
} else if (tok2->str() == "(" && tok2->link()->strAt(1) != "(")
|
||||||
tok2 = tok2->link();
|
tok2 = tok2->link();
|
||||||
|
@ -2940,11 +3024,11 @@ void Tokenizer::setVarIdPass2()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Member variables
|
// Member variables
|
||||||
for (std::list<Token *>::iterator func = allMemberVars.begin(); func != allMemberVars.end(); ++func) {
|
for (std::list<Member>::iterator func = allMemberVars.begin(); func != allMemberVars.end(); ++func) {
|
||||||
if (!Token::simpleMatch(*func, classname.c_str()))
|
if (!Token::simpleMatch(func->tok, classname.c_str()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Token *tok2 = *func;
|
Token *tok2 = func->tok;
|
||||||
tok2 = tok2->tokAt(2);
|
tok2 = tok2->tokAt(2);
|
||||||
tok2->varId(thisClassVars[tok2->str()]);
|
tok2->varId(thisClassVars[tok2->str()]);
|
||||||
}
|
}
|
||||||
|
@ -2953,23 +3037,11 @@ void Tokenizer::setVarIdPass2()
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Set variable ids in member functions for this class..
|
// Set variable ids in member functions for this class..
|
||||||
for (std::list<Token *>::iterator func = allMemberFunctions.begin(); func != allMemberFunctions.end(); ++func) {
|
for (std::list<Member>::const_iterator func = allMemberFunctions.begin(); func != allMemberFunctions.end(); ++func) {
|
||||||
Token *tok2 = *func;
|
Token *tok2 = matchFunctionName(*func, scopeInfo);
|
||||||
|
if (!tok2)
|
||||||
if (!Token::Match(tok2, classname.c_str())) {
|
|
||||||
if (tok2->str() != classname) // #8031: Both could be "A < B >" and if so, one must not bail out
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Token::Match(tok2, "%name% <"))
|
|
||||||
tok2 = tok2->next()->findClosingBracket();
|
|
||||||
|
|
||||||
// Found a class function..
|
|
||||||
if (!Token::Match(tok2, "%any% :: ~| %name%"))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Goto the end parentheses..
|
|
||||||
tok2 = tok2->tokAt(nestedCount*2);
|
|
||||||
if (tok2->str() == "~")
|
if (tok2->str() == "~")
|
||||||
tok2 = tok2->linkAt(2);
|
tok2 = tok2->linkAt(2);
|
||||||
else
|
else
|
||||||
|
|
|
@ -126,7 +126,8 @@ private:
|
||||||
TEST_CASE(varid_in_class18); // #7127
|
TEST_CASE(varid_in_class18); // #7127
|
||||||
TEST_CASE(varid_in_class19);
|
TEST_CASE(varid_in_class19);
|
||||||
TEST_CASE(varid_in_class20); // #7267
|
TEST_CASE(varid_in_class20); // #7267
|
||||||
TEST_CASE(varid_namespace); // #7272
|
TEST_CASE(varid_namespace_1); // #7272
|
||||||
|
TEST_CASE(varid_namespace_2); // #7000
|
||||||
TEST_CASE(varid_initList);
|
TEST_CASE(varid_initList);
|
||||||
TEST_CASE(varid_initListWithBaseTemplate);
|
TEST_CASE(varid_initListWithBaseTemplate);
|
||||||
TEST_CASE(varid_initListWithScope);
|
TEST_CASE(varid_initListWithScope);
|
||||||
|
@ -1764,7 +1765,7 @@ private:
|
||||||
"8: template < class C > cacheEntry < C > :: cacheEntry ( ) : m_key@1 ( ) { }\n", tokenize(code, false, "test.cpp"));
|
"8: template < class C > cacheEntry < C > :: cacheEntry ( ) : m_key@1 ( ) { }\n", tokenize(code, false, "test.cpp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void varid_namespace() { // #7272
|
void varid_namespace_1() { // #7272
|
||||||
const char code[] = "namespace Blah {\n"
|
const char code[] = "namespace Blah {\n"
|
||||||
" struct foo { int x;};\n"
|
" struct foo { int x;};\n"
|
||||||
" struct bar {\n"
|
" struct bar {\n"
|
||||||
|
@ -1781,6 +1782,25 @@ private:
|
||||||
"7: }\n", tokenize(code, false, "test.cpp"));
|
"7: }\n", tokenize(code, false, "test.cpp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void varid_namespace_2() { // #7000
|
||||||
|
const char code[] = "namespace Ui {\n"
|
||||||
|
" class C { int X; };\n" // X@1
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"class C {\n"
|
||||||
|
" void dostuff();\n"
|
||||||
|
" int X;\n" // X@2
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"void C::dostuff() {\n"
|
||||||
|
" X = 0;\n" // X@2
|
||||||
|
"}";
|
||||||
|
|
||||||
|
const std::string actual = tokenize(code, false, "test.cpp");
|
||||||
|
|
||||||
|
ASSERT(actual.find("X@2 = 0") != std::string::npos);
|
||||||
|
}
|
||||||
|
|
||||||
void varid_initList() {
|
void varid_initList() {
|
||||||
const char code1[] = "class A {\n"
|
const char code1[] = "class A {\n"
|
||||||
" A() : x(0) {}\n"
|
" A() : x(0) {}\n"
|
||||||
|
|
Loading…
Reference in New Issue