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

View File

@ -7408,7 +7408,10 @@ private:
"void func1() { }\n" "void func1() { }\n"
"[[noreturn]] void func2();\n" "[[noreturn]] void func2();\n"
"[[noreturn]] void func3() { }\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("", errout.str());
ASSERT_EQUALS(true, db != nullptr); // not null ASSERT_EQUALS(true, db != nullptr); // not null
@ -7428,6 +7431,14 @@ private:
ASSERT_EQUALS(true, func != nullptr); ASSERT_EQUALS(true, func != nullptr);
ASSERT_EQUALS(true, func->isAttributeNoreturn()); 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() { void nodiscardAttributeFunction() {

View File

@ -5691,6 +5691,24 @@ private:
ASSERT_EQUALS("struct a ;", ASSERT_EQUALS("struct a ;",
tokenizeAndStringify("struct [[deprecated,maybe_unused]] alignas(double) [[trivial_abi]] 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() { void simplifyCaseRange() {