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:
IOBYTE 2018-05-08 00:35:51 -04:00 committed by Daniel Marjamäki
parent 58ebc64b2f
commit 8b0b659965
3 changed files with 140 additions and 0 deletions

View File

@ -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();
}
}
}
}

View File

@ -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
* */

View File

@ -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)