Skip to content

Commit

Permalink
fix #13272: false positive: unusedFunction (function attributes) (#7176)
Browse files Browse the repository at this point in the history
  • Loading branch information
ludviggunne authored Jan 7, 2025
1 parent bff9b13 commit 0fdc470
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 3 deletions.
3 changes: 3 additions & 0 deletions lib/checkunusedfunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting
if (func->isAttributeConstructor() || func->isAttributeDestructor() || func->type != Function::eFunction || func->isOperator())
continue;

if (func->isAttributeUnused() || func->isAttributeMaybeUnused())
continue;

if (func->isExtern())
continue;

Expand Down
6 changes: 6 additions & 0 deletions lib/symboldatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,12 @@ class CPPCHECKLIB Function {
bool isAttributeNodiscard() const {
return tokenDef->isAttributeNodiscard();
}
bool isAttributeUnused() const {
return tokenDef->isAttributeUnused();
}
bool isAttributeMaybeUnused() const {
return tokenDef->isAttributeMaybeUnused();
}

bool hasBody() const {
return getFlag(fHasBody);
Expand Down
10 changes: 9 additions & 1 deletion lib/tokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9382,6 +9382,8 @@ void Tokenizer::simplifyCPPAttribute()
// According to cppreference alignas is a c21 feature however the macro is often available when compiling c11
const bool hasAlignas = ((isCPP() && mSettings.standards.cpp >= Standards::CPP11) || (isC() && mSettings.standards.c >= Standards::C11));
const bool hasCppAttribute = ((isCPP() && mSettings.standards.cpp >= Standards::CPP11) || (isC() && mSettings.standards.c >= Standards::C23));
const bool hasMaybeUnused =((isCPP() && mSettings.standards.cpp >= Standards::CPP17) || (isC() && mSettings.standards.c >= Standards::C23));
const bool hasMaybeUnusedUnderscores = (isC() && mSettings.standards.c >= Standards::C23);

if (!hasAlignas && !hasCppAttribute)
return;
Expand Down Expand Up @@ -9414,11 +9416,17 @@ void Tokenizer::simplifyCPPAttribute()
if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
head->previous()->isAttributeNodiscard(true);
}
} else if (Token::findsimplematch(tok->tokAt(2), "maybe_unused", tok->link())) {
} else if ((hasMaybeUnusedUnderscores && Token::findsimplematch(tok->tokAt(2), "__maybe_unused__", tok->link()))
|| (hasMaybeUnused && Token::findsimplematch(tok->tokAt(2), "maybe_unused", tok->link()))) {
Token* head = skipCPPOrAlignAttribute(tok)->next();
while (isCPPAttribute(head) || isAlignAttribute(head))
head = skipCPPOrAlignAttribute(head)->next();
head->isAttributeMaybeUnused(true);
} else if (Token::findsimplematch(tok->tokAt(2), "unused", tok->link())) {
Token* head = skipCPPOrAlignAttribute(tok)->next();
while (isCPPAttribute(head) || isAlignAttribute(head))
head = skipCPPOrAlignAttribute(head)->next();
head->isAttributeUnused(true);
} else if (Token::Match(tok->previous(), ") [ [ expects|ensures|assert default|audit|axiom| : %name% <|<=|>|>= %num% ] ]")) {
const Token *vartok = tok->tokAt(4);
if (vartok->str() == ":")
Expand Down
30 changes: 28 additions & 2 deletions test/testunusedfunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,18 @@ class TestUnusedFunctions : public TestFixture {
TEST_CASE(parensInit);
TEST_CASE(typeInCast);
TEST_CASE(attributeCleanup);
TEST_CASE(attributeUnused);
TEST_CASE(attributeMaybeUnused);
}

#define check(...) check_(__FILE__, __LINE__, __VA_ARGS__)
template<size_t size>
void check_(const char* file, int line, const char (&code)[size], Platform::Type platform = Platform::Type::Native, const Settings *s = nullptr) {
void check_(const char* file, int line, const char (&code)[size], Platform::Type platform = Platform::Type::Native, const Settings *s = nullptr, bool cpp = true) {
const Settings settings1 = settingsBuilder(s ? *s : settings).platform(platform).build();

// Tokenize..
SimpleTokenizer tokenizer(settings1, *this);
ASSERT_LOC(tokenizer.tokenize(code), file, line);
ASSERT_LOC(tokenizer.tokenize(code, cpp), file, line);

// Check for unused functions..
CheckUnusedFunctions checkUnusedFunctions;
Expand Down Expand Up @@ -794,6 +796,30 @@ class TestUnusedFunctions : public TestFixture {
"}\n");
ASSERT_EQUALS("", errout_str());
}

void attributeUnused()
{
check("[[unused]] void f() {}\n");
ASSERT_EQUALS("", errout_str());

check("[[gnu::unused]] void f() {}\n");
ASSERT_EQUALS("", errout_str());

check("__attribute__((unused)) void f() {}\n");
ASSERT_EQUALS("", errout_str());
}

void attributeMaybeUnused()
{
check("[[__maybe_unused__]] void f() {}\n", Platform::Type::Native, nullptr, false);
ASSERT_EQUALS("", errout_str());

check("[[maybe_unused]] void f() {}\n", Platform::Type::Native, nullptr, false);
ASSERT_EQUALS("", errout_str());

check("[[maybe_unused]] void f() {}\n");
ASSERT_EQUALS("", errout_str());
}
};

REGISTER_TEST(TestUnusedFunctions)

0 comments on commit 0fdc470

Please sign in to comment.