diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index ce36f8ff323..8e0b515ca78 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2650,6 +2650,22 @@ namespace { return false; } + if (Token::Match(tok1, "%name% (") && TokenList::isFunctionHead(tok1->next(), "{;:")) { + if (Token::Match(tok1->previous(), "%name%") && !tok1->previous()->isControlFlowKeyword()) + return false; + if (Token::Match(tok1->previous(), ">|>>") && tok1->linkAt(-1)) + return false; + if (Token::Match(tok1->previous(), "*|&|&&")) { + const Token* prev = tok1->previous(); + while (Token::Match(prev, "%name%|*|&|&&|::") && !prev->isControlFlowKeyword()) + prev = prev->previous(); + if (Token::Match(prev, ">|>>") && tok1->linkAt(-1)) + return false; + if (Token::Match(prev, "[;{}] %name%")) + return false; + } + } + // get qualification std::string qualification; const Token* tok2 = tok1; @@ -3027,6 +3043,8 @@ bool Tokenizer::simplifyUsing() } } + bool isTypedefInfoAdded = false; // TODO should we add a separate mUsingInfo? + std::string scope1 = currentScope1->fullName; bool skip = false; // don't erase type aliases we can't parse Token *enumOpenBrace = nullptr; @@ -3097,6 +3115,18 @@ bool Tokenizer::simplifyUsing() } else if (!usingMatch(nameToken, scope, tok1, scope1, currentScope1, nullptr)) continue; + if (!isTypedefInfoAdded && Token::Match(tok1, "%name% (")) { + isTypedefInfoAdded = true; + TypedefInfo usingInfo; + usingInfo.name = name; + usingInfo.filename = list.file(nameToken); + usingInfo.lineNumber = nameToken->linenr(); + usingInfo.column = nameToken->column(); + usingInfo.used = true; + usingInfo.isFunctionPointer = false; + mTypedefInfo.push_back(std::move(usingInfo)); + } + const auto nReplace = tokDistance(start, usingEnd); if (nReplace > maxReplacementTokens) { simplifyUsingError(usingStart, usingEnd); diff --git a/test/testsimplifyusing.cpp b/test/testsimplifyusing.cpp index 6e5206194b4..a9cd23d0a54 100644 --- a/test/testsimplifyusing.cpp +++ b/test/testsimplifyusing.cpp @@ -91,6 +91,7 @@ class TestSimplifyUsing : public TestFixture { TEST_CASE(simplifyUsing10173); TEST_CASE(simplifyUsing10335); TEST_CASE(simplifyUsing10720); + TEST_CASE(simplifyUsing13873); // function declaration TEST_CASE(scopeInfo1); TEST_CASE(scopeInfo2); @@ -1586,6 +1587,20 @@ class TestSimplifyUsing : public TestFixture { TODO_ASSERT(startsWith(errout_str(), "[test.cpp:6]: (debug) Failed to parse 'using C = S < S < S < int")); } + void simplifyUsing13873() { // function declaration + const char code1[] = "using NS1::f;\n" + "namespace NS1 { void f(); }\n"; + ASSERT_EQUALS("namespace NS1 { void f ( ) ; }", tok(code1)); + + const char code2[] = "using NS1::f;\n" + "void bar() { f(); }\n"; + ASSERT_EQUALS("void bar ( ) { NS1 :: f ( ) ; }", tok(code2)); + + const char code3[] = "using NS1::f;\n" + "namespace NS1 { void* f(); }\n"; + ASSERT_EQUALS("namespace NS1 { void * f ( ) ; }", tok(code3)); + } + void scopeInfo1() { const char code[] = "struct A {\n" " enum class Mode { UNKNOWN, ENABLED, NONE, };\n"