Attribute lists support (#3239)
This commit is contained in:
parent
31e3e4d87b
commit
d3035c246f
|
@ -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()) {
|
||||
|
|
|
@ -685,6 +685,11 @@ private:
|
|||
*/
|
||||
void simplifyCallingConvention();
|
||||
|
||||
/**
|
||||
* Split comma-separated attributes
|
||||
*/
|
||||
void simplifyAttributeList();
|
||||
|
||||
/**
|
||||
* Remove \__attribute\__ ((?))
|
||||
*/
|
||||
|
|
|
@ -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;";
|
||||
|
|
Loading…
Reference in New Issue