From b5c25b4a679f0240fd9bd0ea65ae8c8133c9bf6a Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Wed, 8 Oct 2025 20:07:54 +0200 Subject: [PATCH 1/6] Fix #14181 FP nullPointerRedundantCheck / #14183 FP unusedFunction --- lib/tokenize.cpp | 4 +++- test/testtokenize.cpp | 22 ++++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 51506aae8f2..f7f002bbf7d 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, "{;__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..81273ce9b13 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 { } ;"; @@ -4238,7 +4257,6 @@ class TestTokenizer : public TestFixture { ASSERT(var2 && var2->isAttributeMaybeUnused()); } - void splitTemplateRightAngleBrackets() { { const char code[] = "; z = x < 0 ? x >> y : x >> y;"; From 0e89b015337950bf57c561b21a3fe0c2496b004a Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Wed, 8 Oct 2025 20:25:02 +0200 Subject: [PATCH 2/6] Format --- test/testtokenize.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 81273ce9b13..ff386e3005e 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -4257,6 +4257,7 @@ class TestTokenizer : public TestFixture { ASSERT(var2 && var2->isAttributeMaybeUnused()); } + void splitTemplateRightAngleBrackets() { { const char code[] = "; z = x < 0 ? x >> y : x >> y;"; From a27b921d187f66ab823bdbbb2c50543b6e09ecc3 Mon Sep 17 00:00:00 2001 From: chrchr-github Date: Wed, 8 Oct 2025 20:26:15 +0200 Subject: [PATCH 3/6] Format --- test/testtokenize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index ff386e3005e..a103d096b3d 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -4257,7 +4257,7 @@ class TestTokenizer : public TestFixture { ASSERT(var2 && var2->isAttributeMaybeUnused()); } - + void splitTemplateRightAngleBrackets() { { const char code[] = "; z = x < 0 ? x >> y : x >> y;"; From 74cf5ebdd7f216ffbbbf88e3d4136843544fc2c0 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 9 Oct 2025 20:02:53 +0200 Subject: [PATCH 4/6] Update tokenize.cpp --- lib/tokenize.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index f7f002bbf7d..083ca8d768b 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9528,12 +9528,12 @@ 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, "{;__attribute__")) { + if (head && head->str() == "(" && (TokenList::isFunctionHead(head, "{;") || Token::Match(head->link(), ") __attribute__"))) { head->previous()->isAttributeNoreturn(true); } } else if (Token::findsimplematch(tok->tokAt(2), "nodiscard", tok->link())) { Token * head = skipCPPOrAlignAttribute(tok)->next(); - while (isCPPAttribute(head) || isAlignAttribute(head)) + while (isCPPAttribute(head) || isAlignAttribute(head)) head = skipCPPOrAlignAttribute(head)->next(); while (Token::Match(head, "%name%|::|*|&|<|>|,")) head = head->next(); From 1b5061312d4efb43230e5805b940c09da592a742 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 9 Oct 2025 20:06:20 +0200 Subject: [PATCH 5/6] Format --- lib/tokenize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 083ca8d768b..b7d6a097afc 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9533,7 +9533,7 @@ void Tokenizer::simplifyCPPAttribute() } } else if (Token::findsimplematch(tok->tokAt(2), "nodiscard", tok->link())) { Token * head = skipCPPOrAlignAttribute(tok)->next(); - while (isCPPAttribute(head) || isAlignAttribute(head)) + while (isCPPAttribute(head) || isAlignAttribute(head)) head = skipCPPOrAlignAttribute(head)->next(); while (Token::Match(head, "%name%|::|*|&|<|>|,")) head = head->next(); From 47d67d3c3a1fcb37abbbe8230cd8095a40e1e17f Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Thu, 9 Oct 2025 21:42:51 +0200 Subject: [PATCH 6/6] Update tokenize.cpp --- lib/tokenize.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index b7d6a097afc..a9e2d845c20 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9528,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, "{;") || Token::Match(head->link(), ") __attribute__"))) { + 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())) {