diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 51506aae8f2..a9e2d845c20 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9411,6 +9411,8 @@ void Tokenizer::simplifyAttribute() else if (Token::Match(attr, "[(,] unused|__unused__|used|__used__ [,)]")) { Token *vartok = getVariableTokenAfterAttributes(tok); + if (!vartok) + vartok = functok; if (vartok) { const std::string &attribute(attr->strAt(1)); if (attribute.find("unused") != std::string::npos) @@ -9526,7 +9528,7 @@ void Tokenizer::simplifyCPPAttribute() head = skipCPPOrAlignAttribute(head)->next(); while (Token::Match(head, "%name%|::|*|&|<|>|,")) // skip return type head = head->next(); - if (head && head->str() == "(" && TokenList::isFunctionHead(head, "{;")) { + if (head && head->str() == "(" && (TokenList::isFunctionHead(head, "{;") || Token::simpleMatch(head->link(), ") __attribute__"))) { head->previous()->isAttributeNoreturn(true); } } else if (Token::findsimplematch(tok->tokAt(2), "nodiscard", tok->link())) { diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index dceb4975132..a103d096b3d 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -272,7 +272,7 @@ class TestTokenizer : public TestFixture { TEST_CASE(functionAttributeAfter2); TEST_CASE(functionAttributeListBefore); TEST_CASE(functionAttributeListAfter); - + TEST_CASE(functionAttributeListAfter2); TEST_CASE(cppMaybeUnusedBefore); TEST_CASE(cppMaybeUnusedAfter); TEST_CASE(cppMaybeUnusedStructuredBinding); @@ -4197,6 +4197,25 @@ class TestTokenizer : public TestFixture { ASSERT(func8 && func8->isAttributeNoreturn() && func8->isAttributePure() && func8->isAttributeNothrow() && func8->isAttributeConst()); } + void functionAttributeListAfter2() { + const char code[] = "[[noreturn]] void func1(const char *format, ...) __attribute__((format(printf, 1, 2)));\n" // #14181 + "void func2() __attribute__((unused));\n"; // #14183 + const char expected[] = "void func1 ( const char * format , ... ) ; void func2 ( ) ;"; + + // tokenize.. + SimpleTokenizer tokenizer(settings0, *this); + ASSERT(tokenizer.tokenize(code)); + + // Expected result.. + ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false)); + + const Token * func1 = Token::findsimplematch(tokenizer.tokens(), "func1"); + const Token * func2 = Token::findsimplematch(tokenizer.tokens(), "func2"); + + ASSERT(func1 && func1->isAttributeNoreturn()); + ASSERT(func2 && func2->isAttributeUnused()); + } + void cppMaybeUnusedBefore() { const char code[] = "[[maybe_unused]] int var {};"; const char expected[] = "int var { } ;";