Tokenizer: Add attribute for exported symbols (#5043)
This commit is contained in:
parent
d24a1342a6
commit
d5951fa2b9
87
lib/token.h
87
lib/token.h
|
@ -538,6 +538,12 @@ public:
|
||||||
void isAttributeNothrow(const bool value) {
|
void isAttributeNothrow(const bool value) {
|
||||||
setFlag(fIsAttributeNothrow, value);
|
setFlag(fIsAttributeNothrow, value);
|
||||||
}
|
}
|
||||||
|
bool isAttributeExport() const {
|
||||||
|
return getFlag(fIsAttributeExport);
|
||||||
|
}
|
||||||
|
void isAttributeExport(const bool value) {
|
||||||
|
setFlag(fIsAttributeExport, value);
|
||||||
|
}
|
||||||
bool isAttributePacked() const {
|
bool isAttributePacked() const {
|
||||||
return getFlag(fIsAttributePacked);
|
return getFlag(fIsAttributePacked);
|
||||||
}
|
}
|
||||||
|
@ -1278,46 +1284,47 @@ private:
|
||||||
Token *mLink;
|
Token *mLink;
|
||||||
|
|
||||||
enum : uint64_t {
|
enum : uint64_t {
|
||||||
fIsUnsigned = (1 << 0),
|
fIsUnsigned = (1ULL << 0),
|
||||||
fIsSigned = (1 << 1),
|
fIsSigned = (1ULL << 1),
|
||||||
fIsPointerCompare = (1 << 2),
|
fIsPointerCompare = (1ULL << 2),
|
||||||
fIsLong = (1 << 3),
|
fIsLong = (1ULL << 3),
|
||||||
fIsStandardType = (1 << 4),
|
fIsStandardType = (1ULL << 4),
|
||||||
fIsExpandedMacro = (1 << 5),
|
fIsExpandedMacro = (1ULL << 5),
|
||||||
fIsCast = (1 << 6),
|
fIsCast = (1ULL << 6),
|
||||||
fIsAttributeConstructor = (1 << 7), // __attribute__((constructor)) __attribute__((constructor(priority)))
|
fIsAttributeConstructor = (1ULL << 7), // __attribute__((constructor)) __attribute__((constructor(priority)))
|
||||||
fIsAttributeDestructor = (1 << 8), // __attribute__((destructor)) __attribute__((destructor(priority)))
|
fIsAttributeDestructor = (1ULL << 8), // __attribute__((destructor)) __attribute__((destructor(priority)))
|
||||||
fIsAttributeUnused = (1 << 9), // __attribute__((unused))
|
fIsAttributeUnused = (1ULL << 9), // __attribute__((unused))
|
||||||
fIsAttributePure = (1 << 10), // __attribute__((pure))
|
fIsAttributePure = (1ULL << 10), // __attribute__((pure))
|
||||||
fIsAttributeConst = (1 << 11), // __attribute__((const))
|
fIsAttributeConst = (1ULL << 11), // __attribute__((const))
|
||||||
fIsAttributeNoreturn = (1 << 12), // __attribute__((noreturn)), __declspec(noreturn)
|
fIsAttributeNoreturn = (1ULL << 12), // __attribute__((noreturn)), __declspec(noreturn)
|
||||||
fIsAttributeNothrow = (1 << 13), // __attribute__((nothrow)), __declspec(nothrow)
|
fIsAttributeNothrow = (1ULL << 13), // __attribute__((nothrow)), __declspec(nothrow)
|
||||||
fIsAttributeUsed = (1 << 14), // __attribute__((used))
|
fIsAttributeUsed = (1ULL << 14), // __attribute__((used))
|
||||||
fIsAttributePacked = (1 << 15), // __attribute__((packed))
|
fIsAttributePacked = (1ULL << 15), // __attribute__((packed))
|
||||||
fIsAttributeMaybeUnused = (1 << 16), // [[maybe_unsed]]
|
fIsAttributeExport = (1ULL << 16), // __attribute__((__visibility__("default"))), __declspec(dllexport)
|
||||||
fIsControlFlowKeyword = (1 << 17), // if/switch/while/...
|
fIsAttributeMaybeUnused = (1ULL << 17), // [[maybe_unsed]]
|
||||||
fIsOperatorKeyword = (1 << 18), // operator=, etc
|
fIsControlFlowKeyword = (1ULL << 18), // if/switch/while/...
|
||||||
fIsComplex = (1 << 19), // complex/_Complex type
|
fIsOperatorKeyword = (1ULL << 19), // operator=, etc
|
||||||
fIsEnumType = (1 << 20), // enumeration type
|
fIsComplex = (1ULL << 20), // complex/_Complex type
|
||||||
fIsName = (1 << 21),
|
fIsEnumType = (1ULL << 21), // enumeration type
|
||||||
fIsLiteral = (1 << 22),
|
fIsName = (1ULL << 22),
|
||||||
fIsTemplateArg = (1 << 23),
|
fIsLiteral = (1ULL << 23),
|
||||||
fIsAttributeNodiscard = (1 << 24), // __attribute__ ((warn_unused_result)), [[nodiscard]]
|
fIsTemplateArg = (1ULL << 24),
|
||||||
fAtAddress = (1 << 25), // @ 0x4000
|
fIsAttributeNodiscard = (1ULL << 25), // __attribute__ ((warn_unused_result)), [[nodiscard]]
|
||||||
fIncompleteVar = (1 << 26),
|
fAtAddress = (1ULL << 26), // @ 0x4000
|
||||||
fConstexpr = (1 << 27),
|
fIncompleteVar = (1ULL << 27),
|
||||||
fExternC = (1 << 28),
|
fConstexpr = (1ULL << 28),
|
||||||
fIsSplitVarDeclComma = (1 << 29), // set to true when variable declarations are split up ('int a,b;' => 'int a; int b;')
|
fExternC = (1ULL << 29),
|
||||||
fIsSplitVarDeclEq = (1 << 30), // set to true when variable declaration with initialization is split up ('int a=5;' => 'int a; a=5;')
|
fIsSplitVarDeclComma = (1ULL << 30), // set to true when variable declarations are split up ('int a,b;' => 'int a; int b;')
|
||||||
fIsImplicitInt = (1U << 31), // Is "int" token implicitly added?
|
fIsSplitVarDeclEq = (1ULL << 31), // set to true when variable declaration with initialization is split up ('int a=5;' => 'int a; a=5;')
|
||||||
fIsInline = (1ULL << 32), // Is this a inline type
|
fIsImplicitInt = (1ULL << 32), // Is "int" token implicitly added?
|
||||||
fIsTemplate = (1ULL << 33),
|
fIsInline = (1ULL << 33), // Is this a inline type
|
||||||
fIsSimplifedScope = (1ULL << 34), // scope added when simplifying e.g. if (int i = ...; ...)
|
fIsTemplate = (1ULL << 34),
|
||||||
fIsRemovedVoidParameter = (1ULL << 35), // A void function parameter has been removed
|
fIsSimplifedScope = (1ULL << 35), // scope added when simplifying e.g. if (int i = ...; ...)
|
||||||
fIsIncompleteConstant = (1ULL << 36),
|
fIsRemovedVoidParameter = (1ULL << 36), // A void function parameter has been removed
|
||||||
fIsRestrict = (1ULL << 37), // Is this a restrict pointer type
|
fIsIncompleteConstant = (1ULL << 37),
|
||||||
fIsSimplifiedTypedef = (1ULL << 38),
|
fIsRestrict = (1ULL << 38), // Is this a restrict pointer type
|
||||||
fIsFinalType = (1ULL << 39), // Is this a type with final specifier
|
fIsSimplifiedTypedef = (1ULL << 39),
|
||||||
|
fIsFinalType = (1ULL << 40), // Is this a type with final specifier
|
||||||
};
|
};
|
||||||
|
|
||||||
Token::Type mTokType;
|
Token::Type mTokType;
|
||||||
|
|
104
lib/tokenize.cpp
104
lib/tokenize.cpp
|
@ -5802,6 +5802,8 @@ void Tokenizer::dump(std::ostream &out) const
|
||||||
out << " isComplex=\"true\"";
|
out << " isComplex=\"true\"";
|
||||||
if (tok->isRestrict())
|
if (tok->isRestrict())
|
||||||
out << " isRestrict=\"true\"";
|
out << " isRestrict=\"true\"";
|
||||||
|
if (tok->isAttributeExport())
|
||||||
|
out << " isAttributeExport=\"true\"";
|
||||||
if (tok->link())
|
if (tok->link())
|
||||||
out << " link=\"" << tok->link() << '\"';
|
out << " link=\"" << tok->link() << '\"';
|
||||||
if (tok->varId() > 0)
|
if (tok->varId() > 0)
|
||||||
|
@ -8688,20 +8690,65 @@ void Tokenizer::simplifyCallingConvention()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isAttribute(const Token* tok, bool gcc) {
|
||||||
|
return gcc ? Token::Match(tok, "__attribute__|__attribute (") : Token::Match(tok, "__declspec|_declspec (");
|
||||||
|
}
|
||||||
|
|
||||||
|
static Token* getTokenAfterAttributes(Token* tok, bool gccattr) {
|
||||||
|
Token* after = tok;
|
||||||
|
while (isAttribute(after, gccattr))
|
||||||
|
after = after->linkAt(1)->next();
|
||||||
|
return after;
|
||||||
|
}
|
||||||
|
|
||||||
|
Token* Tokenizer::getAttributeFuncTok(Token* tok, bool gccattr) const {
|
||||||
|
if (!Token::Match(tok, "%name% ("))
|
||||||
|
return nullptr;
|
||||||
|
Token* const after = getTokenAfterAttributes(tok, gccattr);
|
||||||
|
if (!after)
|
||||||
|
syntaxError(tok);
|
||||||
|
|
||||||
|
if (Token::Match(after, "%name%|*|&|(")) {
|
||||||
|
Token *ftok = after;
|
||||||
|
while (Token::Match(ftok, "%name%|::|<|*|& !!(")) {
|
||||||
|
if (ftok->str() == "<") {
|
||||||
|
ftok = ftok->findClosingBracket();
|
||||||
|
if (!ftok)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ftok = ftok->next();
|
||||||
|
}
|
||||||
|
if (Token::simpleMatch(ftok, "( *"))
|
||||||
|
ftok = ftok->tokAt(2);
|
||||||
|
if (Token::Match(ftok, "%name% (|)"))
|
||||||
|
return ftok;
|
||||||
|
} else if (Token::Match(after, "[;{=:]")) {
|
||||||
|
Token *prev = tok->previous();
|
||||||
|
while (Token::Match(prev, "%name%"))
|
||||||
|
prev = prev->previous();
|
||||||
|
if (Token::simpleMatch(prev, ")") && Token::Match(prev->link()->previous(), "%name% ("))
|
||||||
|
return prev->link()->previous();
|
||||||
|
else if (Token::simpleMatch(prev, ")") && Token::Match(prev->link()->tokAt(-2), "operator %op% (") && isCPP())
|
||||||
|
return prev->link()->tokAt(-2);
|
||||||
|
else if ((!prev || Token::Match(prev, "[;{}*]")) && Token::Match(tok->previous(), "%name%"))
|
||||||
|
return tok->previous();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void Tokenizer::simplifyDeclspec()
|
void Tokenizer::simplifyDeclspec()
|
||||||
{
|
{
|
||||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||||
while (Token::Match(tok, "__declspec|_declspec (") && tok->next()->link() && tok->next()->link()->next()) {
|
while (isAttribute(tok, false)) {
|
||||||
if (Token::Match(tok->tokAt(2), "noreturn|nothrow")) {
|
Token *functok = getAttributeFuncTok(tok, false);
|
||||||
Token *tok1 = tok->next()->link()->next();
|
if (Token::Match(tok->tokAt(2), "noreturn|nothrow|dllexport")) {
|
||||||
while (tok1 && !Token::Match(tok1, "%name%")) {
|
if (functok) {
|
||||||
tok1 = tok1->next();
|
|
||||||
}
|
|
||||||
if (tok1) {
|
|
||||||
if (tok->strAt(2) == "noreturn")
|
if (tok->strAt(2) == "noreturn")
|
||||||
tok1->isAttributeNoreturn(true);
|
functok->isAttributeNoreturn(true);
|
||||||
|
else if (tok->strAt(2) == "nothrow")
|
||||||
|
functok->isAttributeNothrow(true);
|
||||||
else
|
else
|
||||||
tok1->isAttributeNothrow(true);
|
functok->isAttributeExport(true);
|
||||||
}
|
}
|
||||||
} else if (tok->strAt(2) == "property")
|
} else if (tok->strAt(2) == "property")
|
||||||
tok->next()->link()->insertToken("__property");
|
tok->next()->link()->insertToken("__property");
|
||||||
|
@ -8721,39 +8768,8 @@ void Tokenizer::simplifyAttribute()
|
||||||
if (mSettings->library.isFunctionConst(tok->str(), false))
|
if (mSettings->library.isFunctionConst(tok->str(), false))
|
||||||
tok->isAttributeConst(true);
|
tok->isAttributeConst(true);
|
||||||
}
|
}
|
||||||
while (Token::Match(tok, "__attribute__|__attribute (")) {
|
while (isAttribute(tok, true)) {
|
||||||
Token *after = tok;
|
Token *functok = getAttributeFuncTok(tok, true);
|
||||||
while (Token::Match(after, "__attribute__|__attribute ("))
|
|
||||||
after = after->linkAt(1)->next();
|
|
||||||
if (!after)
|
|
||||||
syntaxError(tok);
|
|
||||||
|
|
||||||
Token *functok = nullptr;
|
|
||||||
if (Token::Match(after, "%name%|*|&|(")) {
|
|
||||||
Token *ftok = after;
|
|
||||||
while (Token::Match(ftok, "%name%|::|<|*|& !!(")) {
|
|
||||||
if (ftok->str() == "<") {
|
|
||||||
ftok = ftok->findClosingBracket();
|
|
||||||
if (!ftok)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ftok = ftok->next();
|
|
||||||
}
|
|
||||||
if (Token::simpleMatch(ftok, "( *"))
|
|
||||||
ftok = ftok->tokAt(2);
|
|
||||||
if (Token::Match(ftok, "%name% (|)"))
|
|
||||||
functok = ftok;
|
|
||||||
} else if (Token::Match(after, "[;{=:]")) {
|
|
||||||
Token *prev = tok->previous();
|
|
||||||
while (Token::Match(prev, "%name%"))
|
|
||||||
prev = prev->previous();
|
|
||||||
if (Token::simpleMatch(prev, ")") && Token::Match(prev->link()->previous(), "%name% ("))
|
|
||||||
functok = prev->link()->previous();
|
|
||||||
else if (Token::simpleMatch(prev, ")") && Token::Match(prev->link()->tokAt(-2), "operator %op% (") && isCPP())
|
|
||||||
functok = prev->link()->tokAt(-2);
|
|
||||||
else if ((!prev || Token::Match(prev, "[;{}*]")) && Token::Match(tok->previous(), "%name%"))
|
|
||||||
functok = tok->previous();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Token *attr = tok->tokAt(2); attr->str() != ")"; attr = attr->next()) {
|
for (Token *attr = tok->tokAt(2); attr->str() != ")"; attr = attr->next()) {
|
||||||
if (Token::Match(attr, "%name% ("))
|
if (Token::Match(attr, "%name% ("))
|
||||||
|
@ -8773,6 +8789,7 @@ void Tokenizer::simplifyAttribute()
|
||||||
|
|
||||||
else if (Token::Match(attr, "[(,] unused|__unused__|used|__used__ [,)]")) {
|
else if (Token::Match(attr, "[(,] unused|__unused__|used|__used__ [,)]")) {
|
||||||
Token *vartok = nullptr;
|
Token *vartok = nullptr;
|
||||||
|
Token *after = getTokenAfterAttributes(tok, true);
|
||||||
|
|
||||||
// check if after variable name
|
// check if after variable name
|
||||||
if (Token::Match(after, ";|=")) {
|
if (Token::Match(after, ";|=")) {
|
||||||
|
@ -8812,6 +8829,9 @@ void Tokenizer::simplifyAttribute()
|
||||||
|
|
||||||
else if (Token::Match(attr, "[(,] packed [,)]") && Token::simpleMatch(tok->previous(), "}"))
|
else if (Token::Match(attr, "[(,] packed [,)]") && Token::simpleMatch(tok->previous(), "}"))
|
||||||
tok->previous()->isAttributePacked(true);
|
tok->previous()->isAttributePacked(true);
|
||||||
|
|
||||||
|
else if (functok && Token::simpleMatch(attr, "( __visibility__ ( \"default\" ) )"))
|
||||||
|
functok->isAttributeExport(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::eraseTokens(tok, tok->linkAt(1)->next());
|
Token::eraseTokens(tok, tok->linkAt(1)->next());
|
||||||
|
|
|
@ -467,6 +467,9 @@ private:
|
||||||
*/
|
*/
|
||||||
void simplifyAttribute();
|
void simplifyAttribute();
|
||||||
|
|
||||||
|
/** Get function token for a attribute */
|
||||||
|
Token* getAttributeFuncTok(Token* tok, bool gccattr) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove \__cppcheck\__ ((?))
|
* Remove \__cppcheck\__ ((?))
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -260,6 +260,7 @@ private:
|
||||||
TEST_CASE(functionAttributeBefore2);
|
TEST_CASE(functionAttributeBefore2);
|
||||||
TEST_CASE(functionAttributeBefore3);
|
TEST_CASE(functionAttributeBefore3);
|
||||||
TEST_CASE(functionAttributeBefore4);
|
TEST_CASE(functionAttributeBefore4);
|
||||||
|
TEST_CASE(functionAttributeBefore5); // __declspec(dllexport)
|
||||||
TEST_CASE(functionAttributeAfter1);
|
TEST_CASE(functionAttributeAfter1);
|
||||||
TEST_CASE(functionAttributeAfter2);
|
TEST_CASE(functionAttributeAfter2);
|
||||||
TEST_CASE(functionAttributeListBefore);
|
TEST_CASE(functionAttributeListBefore);
|
||||||
|
@ -3691,8 +3692,9 @@ private:
|
||||||
"void __attribute__((__pure__)) __attribute__((__nothrow__)) __attribute__((__const__)) func2();\n"
|
"void __attribute__((__pure__)) __attribute__((__nothrow__)) __attribute__((__const__)) func2();\n"
|
||||||
"void __attribute__((nothrow)) __attribute__((pure)) __attribute__((const)) func3();\n"
|
"void __attribute__((nothrow)) __attribute__((pure)) __attribute__((const)) func3();\n"
|
||||||
"void __attribute__((__nothrow__)) __attribute__((__pure__)) __attribute__((__const__)) func4();\n"
|
"void __attribute__((__nothrow__)) __attribute__((__pure__)) __attribute__((__const__)) func4();\n"
|
||||||
"void __attribute__((noreturn)) func5();";
|
"void __attribute__((noreturn)) func5();\n"
|
||||||
const char expected[] = "void func1 ( ) ; void func2 ( ) ; void func3 ( ) ; void func4 ( ) ; void func5 ( ) ;";
|
"void __attribute__((__visibility__(\"default\"))) func6();";
|
||||||
|
const char expected[] = "void func1 ( ) ; void func2 ( ) ; void func3 ( ) ; void func4 ( ) ; void func5 ( ) ; void func6 ( ) ;";
|
||||||
|
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
||||||
|
@ -3709,12 +3711,14 @@ private:
|
||||||
const Token * func3 = Token::findsimplematch(tokenizer.tokens(), "func3");
|
const Token * func3 = Token::findsimplematch(tokenizer.tokens(), "func3");
|
||||||
const Token * func4 = Token::findsimplematch(tokenizer.tokens(), "func4");
|
const Token * func4 = Token::findsimplematch(tokenizer.tokens(), "func4");
|
||||||
const Token * func5 = Token::findsimplematch(tokenizer.tokens(), "func5");
|
const Token * func5 = Token::findsimplematch(tokenizer.tokens(), "func5");
|
||||||
|
const Token * func6 = Token::findsimplematch(tokenizer.tokens(), "func6");
|
||||||
|
|
||||||
ASSERT(func1 && func1->isAttributePure() && func1->isAttributeNothrow() && func1->isAttributeConst());
|
ASSERT(func1 && func1->isAttributePure() && func1->isAttributeNothrow() && func1->isAttributeConst() && !func1->isAttributeExport());
|
||||||
ASSERT(func2 && func2->isAttributePure() && func2->isAttributeNothrow() && func2->isAttributeConst());
|
ASSERT(func2 && func2->isAttributePure() && func2->isAttributeNothrow() && func2->isAttributeConst() && !func2->isAttributeExport());
|
||||||
ASSERT(func3 && func3->isAttributePure() && func3->isAttributeNothrow() && func3->isAttributeConst());
|
ASSERT(func3 && func3->isAttributePure() && func3->isAttributeNothrow() && func3->isAttributeConst() && !func3->isAttributeExport());
|
||||||
ASSERT(func4 && func4->isAttributePure() && func4->isAttributeNothrow() && func4->isAttributeConst());
|
ASSERT(func4 && func4->isAttributePure() && func4->isAttributeNothrow() && func4->isAttributeConst() && !func4->isAttributeExport());
|
||||||
ASSERT(func5 && func5->isAttributeNoreturn());
|
ASSERT(func5 && func5->isAttributeNoreturn());
|
||||||
|
ASSERT(func6 && func6->isAttributeExport());
|
||||||
}
|
}
|
||||||
|
|
||||||
void functionAttributeBefore2() {
|
void functionAttributeBefore2() {
|
||||||
|
@ -3765,6 +3769,25 @@ private:
|
||||||
ASSERT(foo && foo->isAttributeConst());
|
ASSERT(foo && foo->isAttributeConst());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void functionAttributeBefore5() { // __declspec(dllexport)
|
||||||
|
const char code[] = "void __declspec(dllexport) func1();\n";
|
||||||
|
const char expected[] = "void func1 ( ) ;";
|
||||||
|
|
||||||
|
errout.str("");
|
||||||
|
|
||||||
|
// tokenize..
|
||||||
|
Tokenizer tokenizer(&settings0, this);
|
||||||
|
std::istringstream istr(code);
|
||||||
|
ASSERT(tokenizer.tokenize(istr, "test.cpp"));
|
||||||
|
|
||||||
|
// Expected result..
|
||||||
|
ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false));
|
||||||
|
|
||||||
|
const Token * func1 = Token::findsimplematch(tokenizer.tokens(), "func1");
|
||||||
|
|
||||||
|
ASSERT(func1 && func1->isAttributeExport());
|
||||||
|
}
|
||||||
|
|
||||||
void functionAttributeAfter1() {
|
void functionAttributeAfter1() {
|
||||||
const char code[] = "void func1() __attribute__((pure)) __attribute__((nothrow)) __attribute__((const));\n"
|
const char code[] = "void func1() __attribute__((pure)) __attribute__((nothrow)) __attribute__((const));\n"
|
||||||
"void func2() __attribute__((__pure__)) __attribute__((__nothrow__)) __attribute__((__const__));\n"
|
"void func2() __attribute__((__pure__)) __attribute__((__nothrow__)) __attribute__((__const__));\n"
|
||||||
|
|
Loading…
Reference in New Issue