Skip to content

Commit 0fdc470

Browse files
authored
fix #13272: false positive: unusedFunction (function attributes) (#7176)
1 parent bff9b13 commit 0fdc470

File tree

4 files changed

+46
-3
lines changed

4 files changed

+46
-3
lines changed

lib/checkunusedfunctions.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting
8282
if (func->isAttributeConstructor() || func->isAttributeDestructor() || func->type != Function::eFunction || func->isOperator())
8383
continue;
8484

85+
if (func->isAttributeUnused() || func->isAttributeMaybeUnused())
86+
continue;
87+
8588
if (func->isExtern())
8689
continue;
8790

lib/symboldatabase.h

+6
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,12 @@ class CPPCHECKLIB Function {
819819
bool isAttributeNodiscard() const {
820820
return tokenDef->isAttributeNodiscard();
821821
}
822+
bool isAttributeUnused() const {
823+
return tokenDef->isAttributeUnused();
824+
}
825+
bool isAttributeMaybeUnused() const {
826+
return tokenDef->isAttributeMaybeUnused();
827+
}
822828

823829
bool hasBody() const {
824830
return getFlag(fHasBody);

lib/tokenize.cpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -9382,6 +9382,8 @@ void Tokenizer::simplifyCPPAttribute()
93829382
// According to cppreference alignas is a c21 feature however the macro is often available when compiling c11
93839383
const bool hasAlignas = ((isCPP() && mSettings.standards.cpp >= Standards::CPP11) || (isC() && mSettings.standards.c >= Standards::C11));
93849384
const bool hasCppAttribute = ((isCPP() && mSettings.standards.cpp >= Standards::CPP11) || (isC() && mSettings.standards.c >= Standards::C23));
9385+
const bool hasMaybeUnused =((isCPP() && mSettings.standards.cpp >= Standards::CPP17) || (isC() && mSettings.standards.c >= Standards::C23));
9386+
const bool hasMaybeUnusedUnderscores = (isC() && mSettings.standards.c >= Standards::C23);
93859387

93869388
if (!hasAlignas && !hasCppAttribute)
93879389
return;
@@ -9414,11 +9416,17 @@ void Tokenizer::simplifyCPPAttribute()
94149416
if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
94159417
head->previous()->isAttributeNodiscard(true);
94169418
}
9417-
} else if (Token::findsimplematch(tok->tokAt(2), "maybe_unused", tok->link())) {
9419+
} else if ((hasMaybeUnusedUnderscores && Token::findsimplematch(tok->tokAt(2), "__maybe_unused__", tok->link()))
9420+
|| (hasMaybeUnused && Token::findsimplematch(tok->tokAt(2), "maybe_unused", tok->link()))) {
94189421
Token* head = skipCPPOrAlignAttribute(tok)->next();
94199422
while (isCPPAttribute(head) || isAlignAttribute(head))
94209423
head = skipCPPOrAlignAttribute(head)->next();
94219424
head->isAttributeMaybeUnused(true);
9425+
} else if (Token::findsimplematch(tok->tokAt(2), "unused", tok->link())) {
9426+
Token* head = skipCPPOrAlignAttribute(tok)->next();
9427+
while (isCPPAttribute(head) || isAlignAttribute(head))
9428+
head = skipCPPOrAlignAttribute(head)->next();
9429+
head->isAttributeUnused(true);
94229430
} else if (Token::Match(tok->previous(), ") [ [ expects|ensures|assert default|audit|axiom| : %name% <|<=|>|>= %num% ] ]")) {
94239431
const Token *vartok = tok->tokAt(4);
94249432
if (vartok->str() == ":")

test/testunusedfunctions.cpp

+28-2
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,18 @@ class TestUnusedFunctions : public TestFixture {
8686
TEST_CASE(parensInit);
8787
TEST_CASE(typeInCast);
8888
TEST_CASE(attributeCleanup);
89+
TEST_CASE(attributeUnused);
90+
TEST_CASE(attributeMaybeUnused);
8991
}
9092

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

9698
// Tokenize..
9799
SimpleTokenizer tokenizer(settings1, *this);
98-
ASSERT_LOC(tokenizer.tokenize(code), file, line);
100+
ASSERT_LOC(tokenizer.tokenize(code, cpp), file, line);
99101

100102
// Check for unused functions..
101103
CheckUnusedFunctions checkUnusedFunctions;
@@ -794,6 +796,30 @@ class TestUnusedFunctions : public TestFixture {
794796
"}\n");
795797
ASSERT_EQUALS("", errout_str());
796798
}
799+
800+
void attributeUnused()
801+
{
802+
check("[[unused]] void f() {}\n");
803+
ASSERT_EQUALS("", errout_str());
804+
805+
check("[[gnu::unused]] void f() {}\n");
806+
ASSERT_EQUALS("", errout_str());
807+
808+
check("__attribute__((unused)) void f() {}\n");
809+
ASSERT_EQUALS("", errout_str());
810+
}
811+
812+
void attributeMaybeUnused()
813+
{
814+
check("[[__maybe_unused__]] void f() {}\n", Platform::Type::Native, nullptr, false);
815+
ASSERT_EQUALS("", errout_str());
816+
817+
check("[[maybe_unused]] void f() {}\n", Platform::Type::Native, nullptr, false);
818+
ASSERT_EQUALS("", errout_str());
819+
820+
check("[[maybe_unused]] void f() {}\n");
821+
ASSERT_EQUALS("", errout_str());
822+
}
797823
};
798824

799825
REGISTER_TEST(TestUnusedFunctions)

0 commit comments

Comments
 (0)