Remove duplicate namespace aliases so they don't produce syntax errors. (#1222)

* Remove duplicate namespace aliases so they don't produce syntax errors.

DACA2 results showed new SymbolDatabase syntax errors when duplicate
namespace aliases were simplified improperly. The solution is to remove
them in the tokenizer when found.

* Add tests for deleting namespace aliases at end of token list.

* Use eraseTokens to delete multiple tokens at once.
This commit is contained in:
IOBYTE 2018-05-13 02:29:40 -04:00 committed by Daniel Marjamäki
parent 723bacbf09
commit 9ee6068e20
2 changed files with 79 additions and 0 deletions

View File

@ -10247,6 +10247,31 @@ void Tokenizer::simplifyNestedNamespace()
}
}
static bool sameTokens(const Token *first, const Token *last, const Token *other)
{
while (other && first->str() == other->str()) {
if (first == last)
return true;
first = first->next();
other = other->next();
}
return false;
}
static Token * deleteAlias(Token * tok)
{
Token::eraseTokens(tok, Token::findsimplematch(tok, ";"));
// delete first token
tok->deleteThis();
// delete ';' if not last token
tok->deleteThis();
return tok;
}
void Tokenizer::simplifyNamespaceAliases()
{
if (!isCPP())
@ -10281,6 +10306,28 @@ void Tokenizer::simplifyNamespaceAliases()
else if (Token::simpleMatch(tok2, "}"))
endScope--;
else if (tok2->str() == name) {
if (Token::Match(tok2->previous(), "namespace %name% =")) {
// check for possible duplicate aliases
if (sameTokens(tokNameStart, tokNameEnd, tok2->tokAt(2))) {
// delete duplicate
tok2 = deleteAlias(tok2->previous());
continue;
} else {
// conflicting declaration (syntax error)
if (endScope == scope) {
// delete conflicting declaration
tok2 = deleteAlias(tok2->previous());
}
// new declaration
else {
// TODO: use the new alias in this scope
tok2 = deleteAlias(tok2->previous());
}
continue;
}
}
tok2->str(tokNameStart->str());
Token * tok3 = tokNameStart;
while (tok3 != tokNameEnd) {

View File

@ -3546,6 +3546,38 @@ private:
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\"); }"));
// duplicate namespace aliases
ASSERT_EQUALS(";",
tok("namespace ios = boost::iostreams;\nnamespace ios = boost::iostreams;"));
ASSERT_EQUALS(";",
tok("namespace ios = boost::iostreams;\nnamespace ios = boost::iostreams;\nnamespace ios = boost::iostreams;"));
ASSERT_EQUALS("namespace A { namespace B { void foo ( ) { bar ( A :: B :: ab ( ) ) ; } } }",
tok("namespace A::B {"
"namespace AB = A::B;"
"void foo() {"
" namespace AB = A::B;" // duplicate declaration
" bar(AB::ab());"
"}"
"namespace AB = A::B;" //duplicate declaration
"}"));
// redeclared nested namespace aliases
TODO_ASSERT_EQUALS("namespace A { namespace B { void foo ( ) { bar ( A :: B :: ab ( ) ) ; { baz ( A :: a ( ) ) ; } bar ( A :: B :: ab ( ) ) ; } } }",
"namespace A { namespace B { void foo ( ) { bar ( A :: B :: ab ( ) ) ; { baz ( A :: B :: a ( ) ) ; } bar ( A :: B :: ab ( ) ) ; } } }",
tok("namespace A::B {"
"namespace AB = A::B;"
"void foo() {"
" namespace AB = A::B;" // duplicate declaration
" bar(AB::ab());"
" {"
" namespace AB = A;"
" baz(AB::a());" // redeclaration OK
" }"
" bar(AB::ab());"
"}"
"namespace AB = A::B;" //duplicate declaration
"}"));
}
};