Add support for namespace aliases and C++17 nested namespaces. (#1210)
* Add support for namespace aliases and C++17 nested namespaces. These are implemented as tokenizer simplifications so changes are not needed to the tokenizer and symbol database. * Fix codacy warning.
This commit is contained in:
parent
58ebc64b2f
commit
8b0b659965
111
lib/tokenize.cpp
111
lib/tokenize.cpp
|
@ -3577,6 +3577,12 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
|
|||
if (_settings->terminated())
|
||||
return false;
|
||||
|
||||
// convert C++17 style nested namespaces to old style namespaces
|
||||
simplifyNestedNamespace();
|
||||
|
||||
// simplify namespace aliases
|
||||
simplifyNamespaceAliases();
|
||||
|
||||
// Remove [[attribute]]
|
||||
simplifyCPPAttribute();
|
||||
|
||||
|
@ -5617,6 +5623,8 @@ void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, co
|
|||
continue;
|
||||
if (isCPP11 && type0->str() == "using")
|
||||
continue;
|
||||
if (isCPP() && type0->str() == "namespace")
|
||||
continue;
|
||||
|
||||
bool isconst = false;
|
||||
bool isstatic = false;
|
||||
|
@ -10162,3 +10170,106 @@ const Token *Tokenizer::findSQLBlockEnd(const Token *tokSQLStart)
|
|||
|
||||
return tokLastEnd;
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyNestedNamespace()
|
||||
{
|
||||
if (!isCPP())
|
||||
return;
|
||||
|
||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||
if (Token::Match(tok, "namespace %name% ::") && tok->strAt(-1) != "using") {
|
||||
Token * tok2 = tok->tokAt(2);
|
||||
|
||||
// validate syntax
|
||||
while (Token::Match(tok2, ":: %name%"))
|
||||
tok2 = tok2->tokAt(2);
|
||||
|
||||
if (!tok2 || tok2->str() != "{")
|
||||
return; // syntax error
|
||||
|
||||
std::stack<Token *> links;
|
||||
tok2 = tok->tokAt(2);
|
||||
|
||||
while (tok2->str() == "::") {
|
||||
links.push(tok2);
|
||||
tok2->str("{");
|
||||
tok2->insertToken("namespace");
|
||||
tok2 = tok2->tokAt(3);
|
||||
}
|
||||
|
||||
tok = tok2;
|
||||
|
||||
if (!links.empty() && tok2->str() == "{") {
|
||||
tok2 = tok2->link();
|
||||
while (!links.empty()) {
|
||||
tok2->insertToken("}");
|
||||
tok2 = tok2->next();
|
||||
Token::createMutualLinks(links.top(), tok2);
|
||||
links.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyNamespaceAliases()
|
||||
{
|
||||
if (!isCPP())
|
||||
return;
|
||||
|
||||
int scope = 0;
|
||||
|
||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||
if (tok->str() == "{")
|
||||
scope++;
|
||||
else if (tok->str() == "}")
|
||||
scope--;
|
||||
else if (Token::Match(tok, "namespace %name% =")) {
|
||||
const std::string name(tok->next()->str());
|
||||
Token * tokNameStart = tok->tokAt(3);
|
||||
Token * tokNameEnd = tokNameStart;
|
||||
|
||||
while (tokNameEnd && tokNameEnd->next() && tokNameEnd->next()->str() != ";")
|
||||
tokNameEnd = tokNameEnd->next();
|
||||
|
||||
if (!tokNameEnd)
|
||||
return; // syntax error
|
||||
|
||||
int endScope = scope;
|
||||
Token * tokLast = tokNameEnd->next();
|
||||
Token * tokNext = tokLast->next();
|
||||
Token * tok2 = tokNext;
|
||||
|
||||
while (tok2 && endScope >= scope) {
|
||||
if (Token::simpleMatch(tok2, "{"))
|
||||
endScope++;
|
||||
else if (Token::simpleMatch(tok2, "}"))
|
||||
endScope--;
|
||||
else if (tok2->str() == name) {
|
||||
tok2->str(tokNameStart->str());
|
||||
Token * tok3 = tokNameStart;
|
||||
while (tok3 != tokNameEnd) {
|
||||
tok2->insertToken(tok3->next()->str());
|
||||
tok2 = tok2->next();
|
||||
tok3 = tok3->next();
|
||||
}
|
||||
}
|
||||
tok2 = tok2->next();
|
||||
}
|
||||
|
||||
if (tok->previous() && tokNext) {
|
||||
Token::eraseTokens(tok->previous(), tokNext);
|
||||
tok = tokNext->previous();
|
||||
} else if (tok->previous()) {
|
||||
Token::eraseTokens(tok->previous(), tokLast);
|
||||
tok = tokLast;
|
||||
} else if (tokNext) {
|
||||
Token::eraseTokens(tok, tokNext);
|
||||
tok->deleteThis();
|
||||
} else {
|
||||
Token::eraseTokens(tok, tokLast);
|
||||
tok->deleteThis();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -681,6 +681,16 @@ private:
|
|||
* */
|
||||
bool simplifyStrlen();
|
||||
|
||||
/**
|
||||
* Convert namespace aliases
|
||||
*/
|
||||
void simplifyNamespaceAliases();
|
||||
|
||||
/**
|
||||
* Convert C++17 style nested namespace to older style
|
||||
*/
|
||||
void simplifyNestedNamespace();
|
||||
|
||||
/**
|
||||
* Prepare ternary operators with parentheses so that the AST can be created
|
||||
* */
|
||||
|
|
|
@ -226,6 +226,8 @@ private:
|
|||
TEST_CASE(simplifyArrayAddress); // Replace "&str[num]" => "(str + num)"
|
||||
TEST_CASE(simplifyCharAt);
|
||||
TEST_CASE(simplifyOverride); // ticket #5069
|
||||
TEST_CASE(simplifyNestedNamespace);
|
||||
TEST_CASE(simplifyNamespaceAliases);
|
||||
}
|
||||
|
||||
std::string tok(const char code[], bool simplify = true, Settings::PlatformType type = Settings::Native) {
|
||||
|
@ -3528,6 +3530,23 @@ private:
|
|||
ASSERT_EQUALS("void fun ( ) { char override [ 2 ] = { 1 , 2 } ; doSomething ( override , 2 ) ; }",
|
||||
tok(code, true));
|
||||
}
|
||||
|
||||
void simplifyNestedNamespace() {
|
||||
ASSERT_EQUALS("namespace A { namespace B { namespace C { int i ; } } }", tok("namespace A::B::C { int i; }"));
|
||||
}
|
||||
|
||||
void simplifyNamespaceAliases() {
|
||||
ASSERT_EQUALS(";",
|
||||
tok("namespace ios = boost::iostreams;"));
|
||||
ASSERT_EQUALS("boost :: iostreams :: istream foo ( \"foo\" ) ;",
|
||||
tok("namespace ios = boost::iostreams; ios::istream foo(\"foo\");"));
|
||||
ASSERT_EQUALS("boost :: iostreams :: istream foo ( \"foo\" ) ;",
|
||||
tok("using namespace std; namespace ios = boost::iostreams; ios::istream foo(\"foo\");"));
|
||||
ASSERT_EQUALS(";",
|
||||
tok("using namespace std; namespace ios = boost::iostreams;"));
|
||||
ASSERT_EQUALS("namespace NS { boost :: iostreams :: istream foo ( \"foo\" ) ; }",
|
||||
tok("namespace NS { using namespace std; namespace ios = boost::iostreams; ios::istream foo(\"foo\"); }"));
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestSimplifyTokens)
|
||||
|
|
Loading…
Reference in New Issue