Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/tokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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__")) {
Comment thread
chrchr-github marked this conversation as resolved.
Outdated
head->previous()->isAttributeNoreturn(true);
}
} else if (Token::findsimplematch(tok->tokAt(2), "nodiscard", tok->link())) {
Expand Down
21 changes: 20 additions & 1 deletion test/testtokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 { } ;";
Expand Down