From a0b583d05360975e874d546f8985ca66f4040045 Mon Sep 17 00:00:00 2001 From: Anton Lindqvist Date: Sat, 3 Aug 2024 09:13:05 +0200 Subject: [PATCH 1/2] Honor attribute cleanup in unusedFunction Gets rid of FPs when a static function is only used with the attribute cleanup. --- lib/checkunusedfunctions.cpp | 7 +++++++ lib/token.h | 11 +++++++++++ lib/tokenize.cpp | 28 ++++++++++++++++++++++++++++ test/testunusedfunctions.cpp | 10 ++++++++++ 4 files changed, 56 insertions(+) diff --git a/lib/checkunusedfunctions.cpp b/lib/checkunusedfunctions.cpp index 905b05f9a13..b25d93fa832 100644 --- a/lib/checkunusedfunctions.cpp +++ b/lib/checkunusedfunctions.cpp @@ -221,6 +221,13 @@ void CheckUnusedFunctions::parseTokens(const Tokenizer &tokenizer, const Setting } } + if (tok->hasAttributeCleanup()) { + const std::string& funcname = tok->getAttributeCleanup(); + mFunctions[funcname].usedOtherFile = true; + mFunctionCalls.insert(funcname); + continue; + } + const Token *funcname = nullptr; if (doMarkup) diff --git a/lib/token.h b/lib/token.h index 646e5183d4b..683f3b4449b 100644 --- a/lib/token.h +++ b/lib/token.h @@ -133,6 +133,8 @@ struct TokenImpl { mAttributeAlignas->push_back(a); } + std::string mAttributeCleanup; + // For memoization, to speed up parsing of huge arrays #8897 enum class Cpp11init : std::uint8_t { UNKNOWN, CPP11INIT, NOINIT } mCpp11init = Cpp11init::UNKNOWN; @@ -565,6 +567,15 @@ class CPPCHECKLIB Token { void addAttributeAlignas(const std::string& a) { mImpl->addAttributeAlignas(a); } + void addAttributeCleanup(const std::string& funcname) { + mImpl->mAttributeCleanup = funcname; + } + const std::string& getAttributeCleanup() const { + return mImpl->mAttributeCleanup; + } + bool hasAttributeCleanup() const { + return !mImpl->mAttributeCleanup.empty(); + } void setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint value) { mImpl->setCppcheckAttribute(type, value); } diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 100b80240aa..8c09e7e7474 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9146,6 +9146,26 @@ static Token* getTokenAfterAttributes(Token* tok, bool gccattr) { return after; } +static Token* getVariableTokenAfterAttributes(Token* tok) { + Token *vartok = nullptr; + Token *after = getTokenAfterAttributes(tok, true); + + // check if after variable name + if (Token::Match(after, ";|=")) { + Token *prev = tok->previous(); + while (Token::simpleMatch(prev, "]")) + prev = prev->link()->previous(); + if (Token::Match(prev, "%type%")) + vartok = prev; + } + + // check if before variable name + else if (Token::Match(after, "%type%")) + vartok = after; + + return vartok; +} + Token* Tokenizer::getAttributeFuncTok(Token* tok, bool gccattr) const { if (!Token::Match(tok, "%name% (")) return nullptr; @@ -9284,6 +9304,14 @@ void Tokenizer::simplifyAttribute() else if (functok && Token::simpleMatch(attr, "( __visibility__ ( \"default\" ) )")) functok->isAttributeExport(true); + + else if (Token::Match(attr, "[(,] cleanup ( %name% )")) { + Token *vartok = getVariableTokenAfterAttributes(tok); + if (vartok) { + const std::string& funcname = attr->strAt(3); + vartok->addAttributeCleanup(funcname); + } + } } Token::eraseTokens(tok, tok->linkAt(1)->next()); diff --git a/test/testunusedfunctions.cpp b/test/testunusedfunctions.cpp index f33a83cbd02..ab239d0f528 100644 --- a/test/testunusedfunctions.cpp +++ b/test/testunusedfunctions.cpp @@ -85,6 +85,7 @@ class TestUnusedFunctions : public TestFixture { TEST_CASE(virtualFunc); TEST_CASE(parensInit); TEST_CASE(typeInCast); + TEST_CASE(attributeCleanup); } #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) @@ -769,6 +770,15 @@ class TestUnusedFunctions : public TestFixture { "}\n"); ASSERT_EQUALS("[test.cpp:2]: (style) The function 'Type' is never used.\n", errout_str()); } + + void attributeCleanup() + { + check("void clean(void *ptr) {}\n" + "int main() {\n" + " void * __attribute__((cleanup(clean))) p;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); + } }; REGISTER_TEST(TestUnusedFunctions) From d690b9bdb15f650f6ddfdf756c080d99a5608520 Mon Sep 17 00:00:00 2001 From: Anton Lindqvist Date: Sat, 3 Aug 2024 09:19:31 +0200 Subject: [PATCH 2/2] Make further use of getVariableTokenAfterAttributes() helper --- lib/tokenize.cpp | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 8c09e7e7474..5bb49b4de9e 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9257,22 +9257,7 @@ void Tokenizer::simplifyAttribute() } else if (Token::Match(attr, "[(,] unused|__unused__|used|__used__ [,)]")) { - Token *vartok = nullptr; - Token *after = getTokenAfterAttributes(tok, true); - - // check if after variable name - if (Token::Match(after, ";|=")) { - Token *prev = tok->previous(); - while (Token::simpleMatch(prev, "]")) - prev = prev->link()->previous(); - if (Token::Match(prev, "%type%")) - vartok = prev; - } - - // check if before variable name - else if (Token::Match(after, "%type%")) - vartok = after; - + Token *vartok = getVariableTokenAfterAttributes(tok); if (vartok) { const std::string &attribute(attr->strAt(1)); if (attribute.find("unused") != std::string::npos)