diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index d67356ad086..5a0e8335705 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9166,9 +9166,19 @@ void Tokenizer::findGarbageCode() const syntaxError(tok); if (Token::Match(tok, "==|!=|<=|>= %comp%") && tok->strAt(-1) != "operator") syntaxError(tok, tok->str() + " " + tok->strAt(1)); - if (Token::simpleMatch(tok, "::") && (!Token::Match(tok->next(), "%name%|*|~") || - (tok->next()->isKeyword() && !Token::Match(tok->next(), "new|delete|operator")))) - syntaxError(tok); + if (Token::simpleMatch(tok, "::")) { + if (!Token::Match(tok->next(), "%name%|*|~") || (tok->next()->isKeyword() && !Token::Match(tok->next(), "new|delete|operator"))) + syntaxError(tok); + if (Token::simpleMatch(tok->tokAt(-1), ")")) { + const Token* const prev = tok->linkAt(-1)->tokAt(-1); + if (!Token::Match(prev, "%name% (") || (!prev->isControlFlowKeyword() && prev->str() != "decltype")) { + if (prev && prev->isUpperCaseName()) + unknownMacroError(prev); + else + syntaxError(tok); + } + } + } if (Token::Match(tok, "& %comp%|&&|%oror%|&|%or%") && tok->strAt(1) != ">") syntaxError(tok); if (Token::Match(tok, "%comp%|&&|%oror%|&|%or% }") && tok->str() != ">") diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index cbd9eafb8d3..68f51e2c83b 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -3773,9 +3773,8 @@ class TestSymbolDatabase : public TestFixture { } void symboldatabase35() { // ticket #4806 and #4841 - check("class FragmentQueue : public CL_NS(util)::PriorityQueue >\n" - "{};\n"); - ASSERT_EQUALS("", errout_str()); + ASSERT_THROW_INTERNAL(check("class FragmentQueue : public CL_NS(util)::PriorityQueue >\n" + "{};\n"), UNKNOWN_MACRO); } void symboldatabase36() { // ticket #4892 diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index a25ea9c4bd6..e8f369f318a 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -7910,6 +7910,16 @@ class TestTokenizer : public TestFixture { " return std::string{ g() + \"abc\" MACRO \"def\" };\n" "}\n"), UNKNOWN_MACRO); + ASSERT_THROW_INTERNAL(tokenizeAndStringify("namespace N {\n" + " struct C {\n" + " void f();\n" + " };\n" + " void C(abc)::f() {\n" + " X x;\n" + " N::Y([&] { x(); })->g();\n" + " }\n" + "}\n"), UNKNOWN_MACRO); + ASSERT_THROW_INTERNAL_EQUALS(tokenizeAndStringify("static void handle_toggle(void (*proc) PROTO_XT_CALLBACK_ARGS, int var) {}\n"), // #13198 UNKNOWN_MACRO, "There is an unknown macro here somewhere. Configuration is required. If PROTO_XT_CALLBACK_ARGS is a macro then please configure it.");