Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions lib/tokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,15 @@ namespace {
mRangeAfterVar.second = mEndToken;
return;
}
if (Token::Match(type, "%name% (") && Token::simpleMatch(type->linkAt(1), ") ;") && !type->isStandardType()) {
mNameToken = type;
mEndToken = type->linkAt(1)->next();
mRangeType.first = start;
mRangeType.second = type;
mRangeAfterVar.first = mNameToken->next();
mRangeAfterVar.second = mEndToken;
return;
}
}
// TODO: handle all typedefs
if ((false))
Expand All @@ -710,6 +719,15 @@ namespace {
return mUsed;
}

bool isInvalidConstFunctionType(const std::map<std::string, TypedefSimplifier>& m) const {
if (!Token::Match(mTypedefToken, "typedef const %name% %name% ;"))
return false;
const auto it = m.find(mTypedefToken->strAt(2));
if (it == m.end())
return false;
return Token::Match(it->second.mNameToken, "%name% (");
}

bool fail() const {
return mFail;
}
Expand Down Expand Up @@ -823,6 +841,15 @@ namespace {
Token *after = tok3;
while (Token::Match(after, "%name%|*|&|&&|::"))
after = after->next();
if (Token::Match(mNameToken, "%name% (") && Token::simpleMatch(tok3->next(), "*")) {
while (Token::Match(after, "(|["))
after = after->link()->next();
if (after) {
tok3->insertToken("(");
after->previous()->insertToken(")");
Token::createMutualLinks(tok3->next(), after->previous());
}
}

bool useAfterVarRange = true;
if (Token::simpleMatch(mRangeAfterVar.first, "[")) {
Expand Down Expand Up @@ -920,6 +947,8 @@ namespace {
return true;
if (Token::Match(tok->previous(), "; %name% ;"))
return false;
if (Token::Match(tok->previous(), "<|, %name% * ,|>"))
return true;
for (const Token* after = tok->next(); after; after = after->next()) {
if (Token::Match(after, "%name%|::|&|*|&&"))
continue;
Expand Down Expand Up @@ -1014,6 +1043,9 @@ void Tokenizer::simplifyTypedef()
if (indentlevel == 0 && tok->str() == "typedef") {
TypedefSimplifier ts(tok, typeNum);
if (!ts.fail() && numberOfTypedefs[ts.name()] == 1) {
if (mSettings->severity.isEnabled(Severity::portability) && ts.isInvalidConstFunctionType(typedefs))
reportError(tok->next(), Severity::portability, "invalidConstFunctionType",
"It is unspecified behavior to const qualify a function type.");
typedefs.emplace(ts.name(), ts);
if (!ts.isStructEtc())
tok = ts.endToken();
Expand Down
37 changes: 30 additions & 7 deletions test/testsimplifytypedef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class TestSimplifyTypedef : public TestFixture {
private:
// If there are unused templates, keep those
const Settings settings0 = settingsBuilder().severity(Severity::style).checkUnusedTemplates().build();
const Settings settings1 = settingsBuilder().checkUnusedTemplates().build();
const Settings settings1 = settingsBuilder().severity(Severity::portability).checkUnusedTemplates().build();
const Settings settings2 = settingsBuilder().severity(Severity::style).checkUnusedTemplates().build();

void run() override {
Expand All @@ -57,6 +57,9 @@ class TestSimplifyTypedef : public TestFixture {
TEST_CASE(cstruct3);
TEST_CASE(cstruct3);
TEST_CASE(cstruct4);
TEST_CASE(cfunction1);
TEST_CASE(cfunction2);
TEST_CASE(cfunction3);
TEST_CASE(cfp1);
TEST_CASE(cfp2);
TEST_CASE(cfp4);
Expand Down Expand Up @@ -382,6 +385,26 @@ class TestSimplifyTypedef : public TestFixture {
ASSERT_EQUALS("struct s { int a ; int b ; } ; struct s x { } ;", simplifyTypedefC(code));
}

void cfunction1() {
const char code[] = "typedef int callback(int);\n"
"callback* cb;";
ASSERT_EQUALS("int ( * cb ) ( int ) ;", simplifyTypedefC(code));
}

void cfunction2() {
const char code[] = "typedef int callback(int);\n"
"typedef callback* callbackPtr;\n"
"callbackPtr cb;";
ASSERT_EQUALS("int ( * cb ) ( int ) ;", simplifyTypedefC(code));
}

void cfunction3() {
const char code[] = "typedef int f(int);\n"
"typedef const f cf;\n";
simplifyTypedefC(code);
ASSERT_EQUALS("[file.c:2]: (portability) It is unspecified behavior to const qualify a function type.\n", errout.str());
}

void cfp1() {
const char code[] = "typedef void (*fp)(void * p);\n"
"fp x;";
Expand Down Expand Up @@ -3532,7 +3555,7 @@ class TestSimplifyTypedef : public TestFixture {
"func7 f7;";

// The expected result..
const char expected[] = "; C f1 ( ) ; "
const char expected[] = "C f1 ( ) ; "
"C ( * f2 ) ( ) ; "
"C ( & f3 ) ( ) ; "
"C ( * f4 ) ( ) ; "
Expand Down Expand Up @@ -3561,7 +3584,7 @@ class TestSimplifyTypedef : public TestFixture {

// The expected result..
// C const -> const C
const char expected[] = "; const C f1 ( ) ; "
const char expected[] = "const C f1 ( ) ; "
"const C ( * f2 ) ( ) ; "
"const C ( & f3 ) ( ) ; "
"const C ( * f4 ) ( ) ; "
Expand Down Expand Up @@ -3589,7 +3612,7 @@ class TestSimplifyTypedef : public TestFixture {
"func7 f7;";

// The expected result..
const char expected[] = "; const C f1 ( ) ; "
const char expected[] = "const C f1 ( ) ; "
"const C ( * f2 ) ( ) ; "
"const C ( & f3 ) ( ) ; "
"const C ( * f4 ) ( ) ; "
Expand Down Expand Up @@ -3617,7 +3640,7 @@ class TestSimplifyTypedef : public TestFixture {
"func7 f7;";

// The expected result..
const char expected[] = "; C * f1 ( ) ; "
const char expected[] = "C * f1 ( ) ; "
"C * ( * f2 ) ( ) ; "
"C * ( & f3 ) ( ) ; "
"C * ( * f4 ) ( ) ; "
Expand Down Expand Up @@ -3645,7 +3668,7 @@ class TestSimplifyTypedef : public TestFixture {
"func7 f7;";

// The expected result..
const char expected[] = "; const C * f1 ( ) ; "
const char expected[] = "const C * f1 ( ) ; "
"const C * ( * f2 ) ( ) ; "
"const C * ( & f3 ) ( ) ; "
"const C * ( * f4 ) ( ) ; "
Expand Down Expand Up @@ -3674,7 +3697,7 @@ class TestSimplifyTypedef : public TestFixture {

// The expected result..
// C const -> const C
const char expected[] = "; const C * f1 ( ) ; "
const char expected[] = "const C * f1 ( ) ; "
"const C * ( * f2 ) ( ) ; "
"const C * ( & f3 ) ( ) ; "
"const C * ( * f4 ) ( ) ; "
Expand Down
2 changes: 1 addition & 1 deletion test/testtokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3599,7 +3599,7 @@ class TestTokenizer : public TestFixture {
ASSERT_EQUALS("unsigned int ( * f ) ( ) ;", tokenizeAndStringify("unsigned int (*f)();"));
ASSERT_EQUALS("unsigned int * ( * f ) ( ) ;", tokenizeAndStringify("unsigned int * (*f)();"));
ASSERT_EQUALS("void ( * f [ 2 ] ) ( ) ;", tokenizeAndStringify("void (*f[2])();"));
TODO_ASSERT_EQUALS("void ( * f [ 2 ] ) ( ) ;", "void ( * f ) ( void ) [ 2 ] ;", tokenizeAndStringify("typedef void func_t(void); func_t *f[2];"));
ASSERT_EQUALS("void ( * f [ 2 ] ) ( void ) ;", tokenizeAndStringify("typedef void func_t(void); func_t *f[2];"));
}

void simplifyFunctionPointers2() {
Expand Down