Attribute lists support (#3239)

This commit is contained in:
DGarry82 2021-05-01 08:33:55 +03:00 committed by GitHub
parent 31e3e4d87b
commit d3035c246f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 158 additions and 0 deletions

View File

@ -4855,6 +4855,9 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
// Remove [[attribute]] and alignas(?)
simplifyCPPAttribute();
// split comma-separated attributes
simplifyAttributeList();
// remove __attribute__((?))
simplifyAttribute();
@ -10792,6 +10795,71 @@ void Tokenizer::simplifyDeclspec()
}
}
void Tokenizer::simplifyAttributeList()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
while (Token::Match(tok, "__attribute__|__attribute (") &&
tok->next()->link() != tok->next()->next() &&
tok->next()->link() && tok->next()->link()->next()) {
// tokens for braces in __attribute__ (( ))
// (left to right: outerLeftBr, innerLeftBr, innerRightBr, outerRightBr)
Token *outerLeftBr = tok->next(), *outerRightBr = outerLeftBr->link();
Token *innerLeftBr = tok->next()->next(), *innerRightBr = innerLeftBr->link();
// new intermediate __attribute__|__attribute in place of comma
Token *newtok = nullptr;
// new tokens for comma replacement
// __attribute__ ((attr1,attr2)) -> __attribute__ ((attr1)) __attribute__((attr2))
// replaced by ------> \________________/
Token *newInnerRightBr, *newOuterRightBr, *newInnerLeftBr, *newOuterLeftBr;
Token *attrlist = innerLeftBr->next();
// scanning between initial (( and ))
while(attrlist != innerRightBr && !newtok) {
if (attrlist->str() == ",") {
attrlist->insertToken(")"); newInnerRightBr = attrlist->next();
Token::createMutualLinks(innerLeftBr, newInnerRightBr);
newInnerRightBr->insertToken(")"); newOuterRightBr = newInnerRightBr->next();
Token::createMutualLinks(outerLeftBr, newOuterRightBr);
newOuterRightBr->insertToken(tok->str());
newtok = newOuterRightBr->next();
newtok->insertToken("("); newOuterLeftBr = newtok->next();
Token::createMutualLinks(newOuterLeftBr, outerRightBr);
newOuterLeftBr->insertToken("("); newInnerLeftBr = newOuterLeftBr->next();
Token::createMutualLinks(newInnerLeftBr, innerRightBr);
tok = newtok;
// e.g. "," -> ")) __attribute__ (("
Token::replace(attrlist, newInnerRightBr, newInnerLeftBr);
// jump over internal attribute parameters (e.g. format definition)
// example: __attribute__((format(printf, 1, 2), noreturn))
} else if (attrlist->str() == "(") {
attrlist = attrlist->link()->next();
} else {
attrlist = attrlist->next();
}
}
// passing to next token just after __attribute__ ((...))
// (there may be another __attribute__ ((...)) )
if(!newtok) {
tok = outerRightBr->next();
}
}
}
}
void Tokenizer::simplifyAttribute()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {

View File

@ -685,6 +685,11 @@ private:
*/
void simplifyCallingConvention();
/**
* Split comma-separated attributes
*/
void simplifyAttributeList();
/**
* Remove \__attribute\__ ((?))
*/

View File

@ -248,6 +248,8 @@ private:
TEST_CASE(removeattribute);
TEST_CASE(functionAttributeBefore);
TEST_CASE(functionAttributeAfter);
TEST_CASE(functionAttributeListBefore);
TEST_CASE(functionAttributeListAfter);
TEST_CASE(splitTemplateRightAngleBrackets);
@ -3333,6 +3335,89 @@ private:
ASSERT(func5 && func5->isAttributeNoreturn());
}
void functionAttributeListBefore() {
const char code[] = "void __attribute__((pure,nothrow,const)) func1();\n"
"void __attribute__((__pure__,__nothrow__,__const__)) func2();\n"
"void __attribute__((nothrow,pure,const)) func3();\n"
"void __attribute__((__nothrow__,__pure__,__const__)) func4();\n"
"void __attribute__((noreturn,format(printf,1,2))) func5();\n"
"void __attribute__((__nothrow__)) __attribute__((__pure__,__const__)) func6();\n"
"void __attribute__((__nothrow__,__pure__)) __attribute__((__const__)) func7();\n"
"void __attribute__((noreturn)) __attribute__(()) __attribute__((nothrow,pure,const)) func8();";
const char expected[] = "void func1 ( ) ; void func2 ( ) ; void func3 ( ) ; void func4 ( ) ; void func5 ( ) ; "
"void func6 ( ) ; void func7 ( ) ; void func8 ( ) ;";
errout.str("");
// tokenize..
Tokenizer tokenizer(&settings0, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
// Expected result..
ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false));
const Token * func1 = Token::findsimplematch(tokenizer.tokens(), "func1");
const Token * func2 = Token::findsimplematch(tokenizer.tokens(), "func2");
const Token * func3 = Token::findsimplematch(tokenizer.tokens(), "func3");
const Token * func4 = Token::findsimplematch(tokenizer.tokens(), "func4");
const Token * func5 = Token::findsimplematch(tokenizer.tokens(), "func5");
const Token * func6 = Token::findsimplematch(tokenizer.tokens(), "func6");
const Token * func7 = Token::findsimplematch(tokenizer.tokens(), "func7");
const Token * func8 = Token::findsimplematch(tokenizer.tokens(), "func8");
ASSERT(func1 && func1->isAttributePure() && func1->isAttributeNothrow() && func1->isAttributeConst());
ASSERT(func2 && func2->isAttributePure() && func2->isAttributeNothrow() && func2->isAttributeConst());
ASSERT(func3 && func3->isAttributePure() && func3->isAttributeNothrow() && func3->isAttributeConst());
ASSERT(func4 && func4->isAttributePure() && func4->isAttributeNothrow() && func4->isAttributeConst());
ASSERT(func5 && func5->isAttributeNoreturn());
ASSERT(func6 && func6->isAttributePure() && func6->isAttributeNothrow() && func6->isAttributeConst());
ASSERT(func7 && func7->isAttributePure() && func7->isAttributeNothrow() && func7->isAttributeConst());
ASSERT(func8 && func8->isAttributeNoreturn() && func8->isAttributePure() && func8->isAttributeNothrow() && func8->isAttributeConst());
}
void functionAttributeListAfter() {
const char code[] = "void func1() __attribute__((pure,nothrow,const));\n"
"void func2() __attribute__((__pure__,__nothrow__,__const__));\n"
"void func3() __attribute__((nothrow,pure,const));\n"
"void func4() __attribute__((__nothrow__,__pure__,__const__));\n"
"void func5() __attribute__((noreturn,format(printf,1,2)));\n"
"void func6() __attribute__((__nothrow__)) __attribute__((__pure__,__const__));\n"
"void func7() __attribute__((__nothrow__,__pure__)) __attribute__((__const__));\n"
"void func8() __attribute__((noreturn)) __attribute__(()) __attribute__((nothrow,pure,const));";
const char expected[] = "void func1 ( ) ; void func2 ( ) ; void func3 ( ) ; void func4 ( ) ; void func5 ( ) ; "
"void func6 ( ) ; void func7 ( ) ; void func8 ( ) ;";
errout.str("");
// tokenize..
Tokenizer tokenizer(&settings0, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
// Expected result..
ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false));
const Token * func1 = Token::findsimplematch(tokenizer.tokens(), "func1");
const Token * func2 = Token::findsimplematch(tokenizer.tokens(), "func2");
const Token * func3 = Token::findsimplematch(tokenizer.tokens(), "func3");
const Token * func4 = Token::findsimplematch(tokenizer.tokens(), "func4");
const Token * func5 = Token::findsimplematch(tokenizer.tokens(), "func5");
const Token * func6 = Token::findsimplematch(tokenizer.tokens(), "func6");
const Token * func7 = Token::findsimplematch(tokenizer.tokens(), "func7");
const Token * func8 = Token::findsimplematch(tokenizer.tokens(), "func8");
ASSERT(func1 && func1->isAttributePure() && func1->isAttributeNothrow() && func1->isAttributeConst());
ASSERT(func2 && func2->isAttributePure() && func2->isAttributeNothrow() && func2->isAttributeConst());
ASSERT(func3 && func3->isAttributePure() && func3->isAttributeNothrow() && func3->isAttributeConst());
ASSERT(func4 && func4->isAttributePure() && func4->isAttributeNothrow() && func4->isAttributeConst());
ASSERT(func5 && func5->isAttributeNoreturn());
ASSERT(func6 && func6->isAttributePure() && func6->isAttributeNothrow() && func6->isAttributeConst());
ASSERT(func7 && func7->isAttributePure() && func7->isAttributeNothrow() && func7->isAttributeConst());
ASSERT(func8 && func8->isAttributeNoreturn() && func8->isAttributePure() && func8->isAttributeNothrow() && func8->isAttributeConst());
}
void splitTemplateRightAngleBrackets() {
{
const char code[] = "; z = x < 0 ? x >> y : x >> y;";