Fixed #8269 (Tokenizer: wrong varid (using namespace A::B))
This commit is contained in:
parent
2408f01cc0
commit
799f953c00
101
lib/tokenize.cpp
101
lib/tokenize.cpp
|
@ -2860,7 +2860,8 @@ void Tokenizer::setVarIdPass1()
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
struct Member {
|
struct Member {
|
||||||
Member(const std::list<std::string> &s, Token *t) : scope(s), tok(t) {}
|
Member(const std::list<std::string> &s, const std::list<const Token *> ns, Token *t) : usingnamespaces(ns), scope(s), tok(t) {}
|
||||||
|
std::list<const Token *> usingnamespaces;
|
||||||
std::list<std::string> scope;
|
std::list<std::string> scope;
|
||||||
Token *tok;
|
Token *tok;
|
||||||
};
|
};
|
||||||
|
@ -2880,32 +2881,70 @@ static std::string getScopeName(const std::list<ScopeInfo2> &scopeInfo)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Token * matchMemberName(const std::list<std::string> &scope, const Token *nsToken, Token *memberToken, const std::list<ScopeInfo2> &scopeInfo)
|
||||||
|
{
|
||||||
|
std::list<ScopeInfo2>::const_iterator scopeIt = scopeInfo.begin();
|
||||||
|
|
||||||
|
// Current scope..
|
||||||
|
for (std::list<std::string>::const_iterator it = scope.begin(); it != scope.end(); ++it) {
|
||||||
|
if (scopeIt == scopeInfo.end() || scopeIt->name != *it)
|
||||||
|
return nullptr;
|
||||||
|
++scopeIt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// using namespace..
|
||||||
|
if (nsToken) {
|
||||||
|
while (Token::Match(nsToken, "%name% ::")) {
|
||||||
|
if (scopeIt != scopeInfo.end() && nsToken->str() == scopeIt->name) {
|
||||||
|
nsToken = nsToken->tokAt(2);
|
||||||
|
++scopeIt;
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!Token::Match(nsToken, "%name% ;"))
|
||||||
|
return nullptr;
|
||||||
|
if (scopeIt == scopeInfo.end() || nsToken->str() != scopeIt->name)
|
||||||
|
return nullptr;
|
||||||
|
++scopeIt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse member tokens..
|
||||||
|
while (scopeIt != scopeInfo.end()) {
|
||||||
|
if (!Token::Match(memberToken, "%name% ::|<"))
|
||||||
|
return nullptr;
|
||||||
|
if (memberToken->str() != scopeIt->name)
|
||||||
|
return nullptr;
|
||||||
|
if (memberToken->next()->str() == "<") {
|
||||||
|
memberToken = memberToken->next()->findClosingBracket();
|
||||||
|
if (!Token::simpleMatch(memberToken, "> ::"))
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
memberToken = memberToken->tokAt(2);
|
||||||
|
scopeIt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Token::Match(memberToken, "~| %name%") ? memberToken : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
static Token * matchMemberName(const Member &member, const std::list<ScopeInfo2> &scopeInfo)
|
static Token * matchMemberName(const Member &member, const std::list<ScopeInfo2> &scopeInfo)
|
||||||
{
|
{
|
||||||
if (scopeInfo.empty())
|
if (scopeInfo.empty())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
std::list<std::string>::const_iterator memberScopeIt = member.scope.begin();
|
|
||||||
Token *tok2 = member.tok;
|
|
||||||
for (std::list<ScopeInfo2>::const_iterator it = scopeInfo.begin(); tok2 && it != scopeInfo.end(); ++it) {
|
|
||||||
if (memberScopeIt != member.scope.end()) {
|
|
||||||
if (it->name != *memberScopeIt)
|
|
||||||
return nullptr;
|
|
||||||
++memberScopeIt;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Token::Match(tok2, "%name% ::|<"))
|
// Does this member match without "using namespace"..
|
||||||
return nullptr;
|
Token *ret = matchMemberName(member.scope, nullptr, member.tok, scopeInfo);
|
||||||
if (tok2->str() != it->name)
|
if (ret)
|
||||||
return nullptr;
|
return ret;
|
||||||
if (tok2->next()->str() == "<") {
|
|
||||||
tok2 = tok2->next()->findClosingBracket();
|
// Try to match member using the "using namespace ..." namespaces..
|
||||||
if (!Token::simpleMatch(tok2, "> ::"))
|
for (std::list<const Token *>::const_iterator ns = member.usingnamespaces.begin(); ns != member.usingnamespaces.end(); ++ns) {
|
||||||
return nullptr;
|
ret = matchMemberName(member.scope, *ns, member.tok, scopeInfo);
|
||||||
}
|
if (ret)
|
||||||
tok2 = tok2->tokAt(2);
|
return ret;
|
||||||
}
|
}
|
||||||
return (memberScopeIt == member.scope.end() && Token::Match(tok2, "~| %name%")) ? tok2 : nullptr;
|
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token * matchMemberVarName(const Member &var, const std::list<ScopeInfo2> &scopeInfo)
|
static Token * matchMemberVarName(const Member &var, const std::list<ScopeInfo2> &scopeInfo)
|
||||||
|
@ -2917,11 +2956,6 @@ static Token * matchMemberVarName(const Member &var, const std::list<ScopeInfo2>
|
||||||
static Token * matchMemberFunctionName(const Member &func, const std::list<ScopeInfo2> &scopeInfo)
|
static Token * matchMemberFunctionName(const Member &func, const std::list<ScopeInfo2> &scopeInfo)
|
||||||
{
|
{
|
||||||
Token *tok = matchMemberName(func, scopeInfo);
|
Token *tok = matchMemberName(func, scopeInfo);
|
||||||
if (!tok) {
|
|
||||||
const std::list<std::string> emptyScope;
|
|
||||||
const Member m2(emptyScope,func.tok);
|
|
||||||
tok = matchMemberName(m2, scopeInfo);
|
|
||||||
}
|
|
||||||
return Token::Match(tok, "~| %name% (") ? tok : nullptr;
|
return Token::Match(tok, "~| %name% (") ? tok : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2935,11 +2969,16 @@ void Tokenizer::setVarIdPass2()
|
||||||
if (!isC()) {
|
if (!isC()) {
|
||||||
std::map<const Token *, std::string> endOfScope;
|
std::map<const Token *, std::string> endOfScope;
|
||||||
std::list<std::string> scope;
|
std::list<std::string> scope;
|
||||||
|
std::list<const Token *> usingnamespaces;
|
||||||
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 (!tok2->previous() || Token::Match(tok2->previous(), "[;{}]")) {
|
||||||
if (Token::Match(tok2, "using namespace %name% ;"))
|
if (Token::Match(tok2, "using namespace %name% ::|;")) {
|
||||||
scope.push_back(tok2->strAt(2));
|
const Token *endtok = tok2->tokAt(2);
|
||||||
else if (Token::Match(tok2, "namespace %name% {")) {
|
while (Token::Match(endtok, "%name% ::"))
|
||||||
|
endtok = endtok->tokAt(2);
|
||||||
|
if (Token::Match(endtok, "%name% ;"))
|
||||||
|
usingnamespaces.push_back(tok2->tokAt(2));
|
||||||
|
} else if (Token::Match(tok2, "namespace %name% {")) {
|
||||||
scope.push_back(tok2->strAt(1));
|
scope.push_back(tok2->strAt(1));
|
||||||
endOfScope[tok2->linkAt(2)] = tok2->strAt(1);
|
endOfScope[tok2->linkAt(2)] = tok2->strAt(1);
|
||||||
}
|
}
|
||||||
|
@ -2969,9 +3008,9 @@ 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(Member(scope, tok2));
|
allMemberFunctions.push_back(Member(scope, usingnamespaces, tok2));
|
||||||
else if (str3 != "::" && tok2->strAt(-1) != "::") // Support only one depth
|
else if (str3 != "::" && tok2->strAt(-1) != "::") // Support only one depth
|
||||||
allMemberVars.push_back(Member(scope, tok2));
|
allMemberVars.push_back(Member(scope, usingnamespaces, tok2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -182,6 +182,7 @@ private:
|
||||||
TEST_CASE(varidnamespace2);
|
TEST_CASE(varidnamespace2);
|
||||||
TEST_CASE(usingNamespace1);
|
TEST_CASE(usingNamespace1);
|
||||||
TEST_CASE(usingNamespace2);
|
TEST_CASE(usingNamespace2);
|
||||||
|
TEST_CASE(usingNamespace3);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string tokenize(const char code[], bool simplify = false, const char filename[] = "test.cpp") {
|
std::string tokenize(const char code[], bool simplify = false, const char filename[] = "test.cpp") {
|
||||||
|
@ -2875,6 +2876,32 @@ private:
|
||||||
"3: void A :: dostuff ( ) { x@1 = 0 ; }\n";
|
"3: void A :: dostuff ( ) { x@1 = 0 ; }\n";
|
||||||
ASSERT_EQUALS(expected, tokenize(code));
|
ASSERT_EQUALS(expected, tokenize(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void usingNamespace3() {
|
||||||
|
const char code[] = "namespace A {\n"
|
||||||
|
" namespace B {\n"
|
||||||
|
" class C {\n"
|
||||||
|
" double m;\n"
|
||||||
|
" C();\n"
|
||||||
|
" };\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
"using namespace A::B;\n"
|
||||||
|
"C::C() : m(42) {}";
|
||||||
|
|
||||||
|
const char expected[] = "1: namespace A {\n"
|
||||||
|
"2: namespace B {\n"
|
||||||
|
"3: class C {\n"
|
||||||
|
"4: double m@1 ;\n"
|
||||||
|
"5: C ( ) ;\n"
|
||||||
|
"6: } ;\n"
|
||||||
|
"7: }\n"
|
||||||
|
"8: }\n"
|
||||||
|
"9: using namespace A :: B ;\n"
|
||||||
|
"10: C :: C ( ) : m@1 ( 42 ) { }\n";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tokenize(code));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestVarID)
|
REGISTER_TEST(TestVarID)
|
||||||
|
|
Loading…
Reference in New Issue