diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 166662622a3..88316907b99 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -5583,8 +5583,6 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) simplifyFunctionTryCatch(); - simplifyHeadersAndUnusedTemplates(); - // Remove __asm.. simplifyAsm(); @@ -5612,6 +5610,8 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) // remove __attribute__((?)) simplifyAttribute(); + simplifyHeadersAndUnusedTemplates(); + validate(); const SHOWTIME_MODES showTime = mTimerResults ? mSettings.showtime : SHOWTIME_MODES::SHOWTIME_NONE; @@ -6363,7 +6363,7 @@ void Tokenizer::simplifyHeadersAndUnusedTemplates() } } - if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) { + if (!tok->previous() || Token::Match(tok->previous(), "[;{}:]")) { // Remove unused function declarations if (isIncluded && removeUnusedIncludedFunctions) { while (true) { @@ -6396,7 +6396,7 @@ void Tokenizer::simplifyHeadersAndUnusedTemplates() if (removeUnusedTemplates || (isIncluded && removeUnusedIncludedTemplates)) { if (Token::Match(tok, "template < %name%")) { - const Token *closingBracket = tok->next()->findClosingBracket(); + Token *closingBracket = tok->next()->findClosingBracket(); if (Token::Match(closingBracket, "> class|struct %name% [;:{]") && keep.find(closingBracket->strAt(2)) == keep.end()) { const Token *endToken = closingBracket->tokAt(3); if (endToken->str() == ":") { @@ -6410,11 +6410,47 @@ void Tokenizer::simplifyHeadersAndUnusedTemplates() Token::eraseTokens(tok, endToken); tok->deleteThis(); } - } else if (Token::Match(closingBracket, "> %type% %name% (") && Token::simpleMatch(closingBracket->linkAt(3), ") {") && keep.find(closingBracket->strAt(2)) == keep.end()) { - const Token *endToken = closingBracket->linkAt(3)->linkAt(1)->next(); - Token::eraseTokens(tok, endToken); - tok->deleteThis(); - goBack = true; + } else { + Token *funcTok = closingBracket->next(); + while (funcTok) { + if (Token::Match(funcTok, "constexpr|static|inline|const|%type%|&|&&|*") && !Token::Match(funcTok, "%name% (")) { + funcTok = funcTok->next(); + continue; + } + break; + } + if (!Token::Match(funcTok, "%name% (")) { + tok = funcTok; + continue; + } + funcTok = funcTok->linkAt(1); + if (funcTok) { + funcTok = funcTok->next(); + } + while (funcTok) { + if (Token::Match(funcTok, "throw|noexcept (")) { + funcTok = funcTok->linkAt(1); + if (funcTok) { + funcTok = funcTok->next(); + } + continue; + } + if (Token::Match(funcTok, "const|volatile|&|&&")) { + funcTok = funcTok->next(); + continue; + } + break; + } + if (!Token::simpleMatch(funcTok, "{")) { + tok = funcTok; + continue; + } + funcTok = funcTok->link(); + if (funcTok) { + Token::eraseTokens(tok, funcTok->next()); + tok->deleteThis(); + goBack = true; + } } } } diff --git a/test/cli/other_test.py b/test/cli/other_test.py index a747493e48d..a3b61ab355b 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -3164,6 +3164,70 @@ def test_check_unused_templates_func(tmp_path): # #13714 (void)(*((int*)0)); } +class S { +public: + template + void f_t_3() + { + (void)(*((int*)0)); + } +} + +template +static inline void f_t_4() +{ + (void)(*((int*)0)); +} + +template +const void *f_t_5() +{ + (void)(*((int*)0)); +} + +template +void f_t_6() __attribute__((noreturn)) +{ + (void)(*((int*)0)); +} + +template +__attribute__((noreturn)) void f_t_7() +{ + (void)(*((int*)0)); +} + +template +__declspec(noreturn) void f_t_8() +{ + (void)(*((int*)0)); +} + +template +[[noreturn]] void f_t_9() +{ + (void)(*((int*)0)); +} + +template +void f_t_10() noexcept(true) +{ + (void)(*((int*)0)); +} + +template +void f_t_11() throw(true) +{ + (void)(*((int*)0)); +} + +struct S { + template + void f_t_12() const { + (void)(*((int*)0)); + } +}; + void f() {} """)