Fix #8382 (Syntax error when scanning code with template and attribute) (#1089)

* Fix #8382 (Syntax error when scanning code with template and attribute)

This commit only addresses #8382. There are issues concerning which
versions of C++ should be supported and also generic C++ 14 attribute
support which can be revisited later.

* Remove all C++ style attributes.

Remove all C++ style attributes when C++ version is 11 or greater.
Rename simplify function to simplifyCPPAttributes.
Handle more cases of roreturn function attribute.
This commit is contained in:
IOBYTE 2018-02-16 16:25:51 -05:00 committed by Daniel Marjamäki
parent 79be1257ca
commit fcde1d80e9
4 changed files with 71 additions and 20 deletions

View File

@ -3583,8 +3583,8 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
if (_settings->terminated())
return false;
// Remove [[deprecated]]
simplifyDeprecated();
// Remove [[attribute]]
simplifyCPPAttribute();
// remove __attribute__((?))
simplifyAttribute();
@ -8430,7 +8430,8 @@ void Tokenizer::findGarbageCode() const
tok = tok->next()->findClosingBracket();
if (!tok)
syntaxError(tok1);
if (!Token::Match(tok, ">|>> ::| %name%"))
if (!Token::Match(tok, ">|>> ::| %name%") &&
!Token::Match(tok, ">|>> [ [ %name%"))
syntaxError(tok->next() ? tok->next() : tok1);
}
}
@ -8915,6 +8916,26 @@ void Tokenizer::simplifyAttribute()
}
}
void Tokenizer::simplifyCPPAttribute()
{
if (_settings->standards.cpp < Standards::CPP11 || isC())
return;
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->link() && Token::Match(tok, "[ [ %name%")) {
if (tok->strAt(2) == "noreturn") {
const Token * head = tok->tokAt(5);
while (Token::Match(head, "%name%|::|*|&"))
head = head->next();
if (head && isFunctionHead(head, "{|;"))
head->previous()->isAttributeNoreturn(true);
}
Token::eraseTokens(tok, tok->link()->next());
tok->deleteThis();
}
}
}
static const std::set<std::string> keywords = make_container< std::set<std::string> >()
<< "volatile"
<< "inline"
@ -9811,19 +9832,6 @@ void Tokenizer::removeUnnecessaryQualification()
}
}
void Tokenizer::simplifyDeprecated()
{
if (_settings->standards.cpp != Standards::CPP11 || isC())
return; // It is actually a C++14 feature, however, there seems to be nothing dangerous about removing it for C++11 as well
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->link() && Token::simpleMatch(tok, "[ [ deprecated")) {
Token::eraseTokens(tok, tok->link()->next());
tok->deleteThis();
}
}
}
void Tokenizer::simplifyReturnStrncat()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {

View File

@ -671,9 +671,9 @@ private:
void simplifyOperatorName();
/**
* Remove [[deprecated]] (C++14) from TokenList
* Remove [[attribute]] (C++11 and later) from TokenList
*/
void simplifyDeprecated();
void simplifyCPPAttribute();
/**
* Replace strlen(str)

View File

@ -316,6 +316,8 @@ private:
TEST_CASE(nothrowAttributeFunction);
TEST_CASE(nothrowDeclspecFunction);
TEST_CASE(noreturnAttributeFunction);
TEST_CASE(varTypesIntegral); // known integral
TEST_CASE(varTypesFloating); // known floating
TEST_CASE(varTypesOther); // (un)known
@ -4115,6 +4117,35 @@ private:
}
}
void noreturnAttributeFunction() {
GET_SYMBOL_DB("[[noreturn]] void func1();\n"
"void func1() { }\n"
"[[noreturn]] void func2();\n"
"[[noreturn]] void func3() { }\n"
"template <class T> [[noreturn]] void func4() { }");
ASSERT_EQUALS("", errout.str());
ASSERT_EQUALS(true, db != nullptr); // not null
if (db) {
const Function *func = findFunctionByName("func1", &db->scopeList.front());
ASSERT_EQUALS(true, func != nullptr);
if (func)
ASSERT_EQUALS(true, func->isAttributeNoreturn());
func = findFunctionByName("func2", &db->scopeList.front());
ASSERT_EQUALS(true, func != nullptr);
if (func)
ASSERT_EQUALS(true, func->isAttributeNoreturn());
func = findFunctionByName("func3", &db->scopeList.front());
ASSERT_EQUALS(true, func != nullptr);
if (func)
ASSERT_EQUALS(true, func->isAttributeNoreturn());
func = findFunctionByName("func4", &db->scopeList.front());
ASSERT_EQUALS(true, func != nullptr);
if (func)
ASSERT_EQUALS(true, func->isAttributeNoreturn());
}
}
void varTypesIntegral() {
GET_SYMBOL_DB("void f() { bool b; char c; unsigned char uc; short s; unsigned short us; int i; unsigned u; unsigned int ui; long l; unsigned long ul; long long ll; }");
const Variable *b = db->getVariableFromVarId(1);

View File

@ -440,7 +440,7 @@ private:
TEST_CASE(simplifyMathExpressions); //ticket #1620
TEST_CASE(simplifyStaticConst);
TEST_CASE(simplifyDeprecated);
TEST_CASE(simplifyCPPAttribute);
TEST_CASE(simplifyCaseRange);
@ -7972,7 +7972,7 @@ private:
ASSERT_EQUALS(expected3, tokenizeAndStringify(code3, true));
}
void simplifyDeprecated() {
void simplifyCPPAttribute() {
ASSERT_EQUALS("int f ( ) ;",
tokenizeAndStringify("[[deprecated]] int f();", false, true, Settings::Native, "test.cpp", true));
@ -7981,6 +7981,18 @@ private:
ASSERT_EQUALS("[ [ deprecated ] ] int f ( ) ;",
tokenizeAndStringify("[[deprecated]] int f();", false, true, Settings::Native, "test.c", true));
ASSERT_EQUALS("template < class T > int f ( ) { }",
tokenizeAndStringify("template <class T> [[noreturn]] int f(){}", false, true, Settings::Native, "test.cpp", true));
ASSERT_EQUALS("template < class T > [ [ noreturn ] ] int f ( ) { }",
tokenizeAndStringify("template <class T> [[noreturn]] int f(){}", false, true, Settings::Native, "test.cpp", false));
ASSERT_EQUALS("int f ( int i ) ;",
tokenizeAndStringify("[[maybe_unused]] int f([[maybe_unused]] int i);", false, true, Settings::Native, "test.cpp", true));
ASSERT_EQUALS("[ [ maybe_unused ] ] int f ( [ [ maybe_unused ] ] int i ) ;",
tokenizeAndStringify("[[maybe_unused]] int f([[maybe_unused]] int i);", false, true, Settings::Native, "test.cpp", false));
}
void simplifyCaseRange() {