fix skipping of cpp attributes. (#4971)

* fix skipping of cpp attributes.

* fix simplifyCPPAttribute loop.

When the first token was the start of a c++ attribute on a function,
so that tok->previous() was nullptr at the bottom of the loop,
an extra token would be skipped.  This could result in the corresponding
function being omitted from the symbol table.

* fix alignas test failure, enhance cpp attr test.

* uncrustify.

* fix redundantNextPrevious

* delete redundant code.

* add some tokenizer tests for simplifyCPPAttribute.

* enhance noreturn symbol test.

The order of a noreturn attribute and another attribute used to
matter.  Test both orders.
This commit is contained in:
tsteven4 2023-04-17 12:36:25 -06:00 committed by GitHub
parent c3002f1230
commit 4183336dc1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 19 deletions

View File

@ -8825,36 +8825,35 @@ void Tokenizer::simplifyCPPAttribute()
if (mSettings->standards.cpp < Standards::CPP11 || isC())
return;
for (Token *tok = list.front(); tok; tok = tok->next()) {
for (Token *tok = list.front(); tok;) {
if (!isCPPAttribute(tok) && !isAlignAttribute(tok)) {
tok = tok->next();
continue;
}
if (isCPPAttribute(tok)) {
if (Token::findsimplematch(tok->tokAt(2), "noreturn", tok->link())) {
Token * head = skipCPPOrAlignAttribute(tok);
Token * head = skipCPPOrAlignAttribute(tok)->next();
while (isCPPAttribute(head) || isAlignAttribute(head))
head = skipCPPOrAlignAttribute(head);
head = head->next();
head = skipCPPOrAlignAttribute(head)->next();
while (Token::Match(head, "%name%|::|*|&|<|>|,")) // skip return type
head = head->next();
if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
head->previous()->isAttributeNoreturn(true);
}
} else if (Token::findsimplematch(tok->tokAt(2), "nodiscard", tok->link())) {
Token * head = skipCPPOrAlignAttribute(tok);
Token * head = skipCPPOrAlignAttribute(tok)->next();
while (isCPPAttribute(head) || isAlignAttribute(head))
head = skipCPPOrAlignAttribute(head);
head = head->next();
head = skipCPPOrAlignAttribute(head)->next();
while (Token::Match(head, "%name%|::|*|&|<|>|,"))
head = head->next();
if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
head->previous()->isAttributeNodiscard(true);
}
} else if (Token::findsimplematch(tok->tokAt(2), "maybe_unused", tok->link())) {
Token* head = skipCPPOrAlignAttribute(tok);
Token* head = skipCPPOrAlignAttribute(tok)->next();
while (isCPPAttribute(head) || isAlignAttribute(head))
head = skipCPPOrAlignAttribute(head);
head->next()->isAttributeMaybeUnused(true);
head = skipCPPOrAlignAttribute(head)->next();
head->isAttributeMaybeUnused(true);
} else if (Token::Match(tok->previous(), ") [ [ expects|ensures|assert default|audit|axiom| : %name% <|<=|>|>= %num% ] ]")) {
const Token *vartok = tok->tokAt(4);
if (vartok->str() == ":")
@ -8884,14 +8883,7 @@ void Tokenizer::simplifyCPPAttribute()
}
}
Token::eraseTokens(tok, skipCPPOrAlignAttribute(tok)->next());
// fix iterator after removing
if (tok->previous()) {
tok = tok->previous();
tok->next()->deleteThis();
} else {
tok->deleteThis();
tok = list.front();
}
tok->deleteThis();
}
}

View File

@ -7408,7 +7408,10 @@ private:
"void func1() { }\n"
"[[noreturn]] void func2();\n"
"[[noreturn]] void func3() { }\n"
"template <class T> [[noreturn]] void func4() { }");
"template <class T> [[noreturn]] void func4() { }\n"
"[[noreturn]] [[gnu::format(printf, 1, 2)]] void func5(const char*, ...);\n"
"[[gnu::format(printf, 1, 2)]] [[noreturn]] void func6(const char*, ...);\n"
);
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS(true, db != nullptr); // not null
@ -7428,6 +7431,14 @@ private:
ASSERT_EQUALS(true, func != nullptr);
ASSERT_EQUALS(true, func->isAttributeNoreturn());
func = findFunctionByName("func5", &db->scopeList.front());
ASSERT_EQUALS(true, func != nullptr);
ASSERT_EQUALS(true, func->isAttributeNoreturn());
func = findFunctionByName("func6", &db->scopeList.front());
ASSERT_EQUALS(true, func != nullptr);
ASSERT_EQUALS(true, func->isAttributeNoreturn());
}
void nodiscardAttributeFunction() {

View File

@ -5691,6 +5691,24 @@ private:
ASSERT_EQUALS("struct a ;",
tokenizeAndStringify("struct [[deprecated,maybe_unused]] alignas(double) [[trivial_abi]] a;"));
ASSERT_EQUALS("void func5 ( const char * , ... ) ;",
tokenizeAndStringify("[[noreturn]] void func5(const char*, ...);"));
ASSERT_EQUALS("void func5 ( const char * , ... ) ;",
tokenizeAndStringify("[[noreturn]] [[gnu::format(printf, 1, 2)]] void func5(const char*, ...);"));
ASSERT_EQUALS("void func5 ( const char * , ... ) ;",
tokenizeAndStringify("[[gnu::format(printf, 1, 2)]] [[noreturn]] void func5(const char*, ...);"));
ASSERT_EQUALS("int func1 ( ) ;",
tokenizeAndStringify("[[nodiscard]] int func1();"));
ASSERT_EQUALS("int func1 ( ) ;",
tokenizeAndStringify("[[nodiscard]] [[clang::optnone]] int func1();"));
ASSERT_EQUALS("int func1 ( ) ;",
tokenizeAndStringify("[[clang::optnone]] [[nodiscard]] int func1();"));
}
void simplifyCaseRange() {