simplifyCPPAttribute tokenizer strips alignas (#3171)

This commit is contained in:
Tetrix 2021-03-20 10:38:47 +01:00 committed by GitHub
parent ab33bf1da8
commit 9b7f1f6280
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 143 additions and 40 deletions

View File

@ -4816,7 +4816,7 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
// simplify namespace aliases
simplifyNamespaceAliases();
// Remove [[attribute]]
// Remove [[attribute]] and alignas(?)
simplifyCPPAttribute();
// remove __attribute__((?))
@ -9919,6 +9919,21 @@ static bool isCPPAttribute(const Token * tok)
return Token::simpleMatch(tok, "[ [") && tok->link() && tok->link()->previous() == tok->linkAt(1);
}
static bool isAlignAttribute(const Token * tok)
{
return Token::simpleMatch(tok, "alignas (") && tok->next()->link();
}
static const Token* skipCPPOrAlignAttribute(const Token * tok)
{
if(isCPPAttribute(tok)) {
return tok->link();
}else if(isAlignAttribute(tok)) {
return tok->next()->link();
}
return tok;
}
void Tokenizer::reportUnknownMacros() const
{
// Report unknown macros used in expressions "%name% %num%"
@ -10182,8 +10197,8 @@ void Tokenizer::findGarbageCode() const
continue;
}
// skip C++ attributes [[...]]
if (isCPP11 && isCPPAttribute(tok)) {
tok = tok->link();
if (isCPP11 && (isCPPAttribute(tok) || isAlignAttribute(tok)) ) {
tok = skipCPPOrAlignAttribute(tok);
continue;
}
{
@ -10825,48 +10840,72 @@ void Tokenizer::simplifyCPPAttribute()
return;
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (!isCPPAttribute(tok))
if (!isCPPAttribute(tok) && !isAlignAttribute(tok)){
continue;
if (Token::Match(tok->tokAt(2), "noreturn|nodiscard")) {
const Token * head = tok->link()->next();
while (Token::Match(head, "%name%|::|*|&"))
}
if(isCPPAttribute(tok)){
if (Token::findsimplematch(tok->tokAt(2), "noreturn", tok->link())) {
const Token * head = skipCPPOrAlignAttribute(tok);
while (isCPPAttribute(head) || isAlignAttribute(head))
head = skipCPPOrAlignAttribute(head);
head = head->next();
if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
if (tok->strAt(2) == "noreturn")
head->previous()->isAttributeNoreturn(true);
else
head->previous()->isAttributeNodiscard(true);
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())) {
const Token * head = skipCPPOrAlignAttribute(tok);
while (isCPPAttribute(head) || isAlignAttribute(head))
head = skipCPPOrAlignAttribute(head);
head = 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())) {
const Token* head = skipCPPOrAlignAttribute(tok);
while (isCPPAttribute(head) || isAlignAttribute(head))
head = skipCPPOrAlignAttribute(head);
head->next()->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() == ":")
vartok = vartok->next();
Token *argtok = tok->tokAt(-2);
while (argtok && argtok->str() != "(") {
if (argtok->str() == vartok->str())
break;
if (argtok->str() == ")")
argtok = argtok->link();
argtok = argtok->previous();
}
if (argtok && argtok->str() == vartok->str()) {
if (vartok->next()->str() == ">=")
argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, MathLib::toLongNumber(vartok->strAt(2)));
else if (vartok->next()->str() == ">")
argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, MathLib::toLongNumber(vartok->strAt(2))+1);
else if (vartok->next()->str() == "<=")
argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, MathLib::toLongNumber(vartok->strAt(2)));
else if (vartok->next()->str() == "<")
argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, MathLib::toLongNumber(vartok->strAt(2))-1);
}
}
} else if (Token::simpleMatch(tok->tokAt(2), "maybe_unused")) {
Token* head = tok->tokAt(5);
while (isCPPAttribute(head))
head = head->tokAt(5);
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() == ":")
vartok = vartok->next();
Token *argtok = tok->tokAt(-2);
while (argtok && argtok->str() != "(") {
if (argtok->str() == vartok->str())
break;
if (argtok->str() == ")")
argtok = argtok->link();
argtok = argtok->previous();
}
if (argtok && argtok->str() == vartok->str()) {
if (vartok->next()->str() == ">=")
argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, MathLib::toLongNumber(vartok->strAt(2)));
else if (vartok->next()->str() == ">")
argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, MathLib::toLongNumber(vartok->strAt(2))+1);
else if (vartok->next()->str() == "<=")
argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, MathLib::toLongNumber(vartok->strAt(2)));
else if (vartok->next()->str() == "<")
argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, MathLib::toLongNumber(vartok->strAt(2))-1);
} else {
if (Token::simpleMatch(tok, "alignas (")) {
// alignment requirements could be checked here
}
}
Token::eraseTokens(tok, tok->link()->next());
tok->deleteThis();
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();
}
}
}

View File

@ -345,6 +345,7 @@ private:
TEST_CASE(symboldatabase90);
TEST_CASE(symboldatabase91);
TEST_CASE(symboldatabase92); // daca crash
TEST_CASE(symboldatabase93); // alignas attribute
TEST_CASE(createSymbolDatabaseFindAllScopes1);
@ -426,6 +427,7 @@ private:
TEST_CASE(nothrowDeclspecFunction);
TEST_CASE(noreturnAttributeFunction);
TEST_CASE(nodiscardAttributeFunction);
TEST_CASE(varTypesIntegral); // known integral
TEST_CASE(varTypesFloating); // known floating
@ -4689,6 +4691,15 @@ private:
ASSERT_EQUALS("", errout.str());
}
void symboldatabase93() { // alignas attribute
GET_SYMBOL_DB("struct alignas(int) A{\n"
"};\n"
);
ASSERT(db != nullptr);
const Scope* scope = db->findScopeByName("A");
ASSERT(scope);
}
void createSymbolDatabaseFindAllScopes1() {
GET_SYMBOL_DB("void f() { union {int x; char *p;} a={0}; }");
ASSERT(db->scopeList.size() == 3);
@ -6647,6 +6658,44 @@ private:
func = findFunctionByName("func4", &db->scopeList.front());
ASSERT_EQUALS(true, func != nullptr);
ASSERT_EQUALS(true, func->isAttributeNoreturn());
}
void nodiscardAttributeFunction() {
GET_SYMBOL_DB("[[nodiscard]] int func1();\n"
"int func1() { }\n"
"[[nodiscard]] int func2();\n"
"[[nodiscard]] int func3() { }\n"
"template <class T> [[nodiscard]] int func4() { }"
"std::pair<bool, char> [[nodiscard]] func5();\n"
"[[nodiscard]] std::pair<bool, char> func6();\n"
);
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS(true, db != nullptr); // not null
const Function *func = findFunctionByName("func1", &db->scopeList.front());
ASSERT_EQUALS(true, func != nullptr);
ASSERT_EQUALS(true, func->isAttributeNodiscard());
func = findFunctionByName("func2", &db->scopeList.front());
ASSERT_EQUALS(true, func != nullptr);
ASSERT_EQUALS(true, func->isAttributeNodiscard());
func = findFunctionByName("func3", &db->scopeList.front());
ASSERT_EQUALS(true, func != nullptr);
ASSERT_EQUALS(true, func->isAttributeNodiscard());
func = findFunctionByName("func4", &db->scopeList.front());
ASSERT_EQUALS(true, func != nullptr);
ASSERT_EQUALS(true, func->isAttributeNodiscard());
func = findFunctionByName("func5", &db->scopeList.front());
ASSERT_EQUALS(true, func != nullptr);
ASSERT_EQUALS(true, func->isAttributeNodiscard());
func = findFunctionByName("func6", &db->scopeList.front());
ASSERT_EQUALS(true, func != nullptr);
ASSERT_EQUALS(true, func->isAttributeNodiscard());
}
void varTypesIntegral() {

View File

@ -5690,6 +5690,21 @@ private:
ASSERT_EQUALS("struct a ;",
tokenizeAndStringify("struct [[,,,]] a;", false, true, Settings::Native, "test.cpp", true));
ASSERT_EQUALS("struct a ;",
tokenizeAndStringify("struct alignas(int) a;", false, true, Settings::Native, "test.cpp", true));
ASSERT_EQUALS("struct a ;",
tokenizeAndStringify("struct alignas ( alignof ( float ) ) a;", false, true, Settings::Native, "test.cpp", true));
ASSERT_EQUALS("char a [ 256 ] ;",
tokenizeAndStringify("alignas(256) char a[256];", false, true, Settings::Native, "test.cpp", true));
ASSERT_EQUALS("struct a ;",
tokenizeAndStringify("struct alignas(float) [[deprecated(reason)]] a;", false, true, Settings::Native, "test.cpp", true));
ASSERT_EQUALS("struct a ;",
tokenizeAndStringify("struct [[deprecated,maybe_unused]] alignas(double) [[trivial_abi]] a;", false, true, Settings::Native, "test.cpp", true));
}
void simplifyCaseRange() {