diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 84fd46764..b608d1fb7 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -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) { diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 5fd61ab41..79a026006 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -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 + "}")); } };