Skip to content

Commit 2b74a20

Browse files
authored
Fixed #11716 (simplifyTypedef: function with const should be handled better) (cppcheck-opensource#5054)
1 parent aa6df06 commit 2b74a20

3 files changed

Lines changed: 63 additions & 8 deletions

File tree

lib/tokenize.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,15 @@ namespace {
695695
mRangeAfterVar.second = mEndToken;
696696
return;
697697
}
698+
if (Token::Match(type, "%name% (") && Token::simpleMatch(type->linkAt(1), ") ;") && !type->isStandardType()) {
699+
mNameToken = type;
700+
mEndToken = type->linkAt(1)->next();
701+
mRangeType.first = start;
702+
mRangeType.second = type;
703+
mRangeAfterVar.first = mNameToken->next();
704+
mRangeAfterVar.second = mEndToken;
705+
return;
706+
}
698707
}
699708
// TODO: handle all typedefs
700709
if ((false))
@@ -710,6 +719,15 @@ namespace {
710719
return mUsed;
711720
}
712721

722+
bool isInvalidConstFunctionType(const std::map<std::string, TypedefSimplifier>& m) const {
723+
if (!Token::Match(mTypedefToken, "typedef const %name% %name% ;"))
724+
return false;
725+
const auto it = m.find(mTypedefToken->strAt(2));
726+
if (it == m.end())
727+
return false;
728+
return Token::Match(it->second.mNameToken, "%name% (");
729+
}
730+
713731
bool fail() const {
714732
return mFail;
715733
}
@@ -823,6 +841,15 @@ namespace {
823841
Token *after = tok3;
824842
while (Token::Match(after, "%name%|*|&|&&|::"))
825843
after = after->next();
844+
if (Token::Match(mNameToken, "%name% (") && Token::simpleMatch(tok3->next(), "*")) {
845+
while (Token::Match(after, "(|["))
846+
after = after->link()->next();
847+
if (after) {
848+
tok3->insertToken("(");
849+
after->previous()->insertToken(")");
850+
Token::createMutualLinks(tok3->next(), after->previous());
851+
}
852+
}
826853

827854
bool useAfterVarRange = true;
828855
if (Token::simpleMatch(mRangeAfterVar.first, "[")) {
@@ -920,6 +947,8 @@ namespace {
920947
return true;
921948
if (Token::Match(tok->previous(), "; %name% ;"))
922949
return false;
950+
if (Token::Match(tok->previous(), "<|, %name% * ,|>"))
951+
return true;
923952
for (const Token* after = tok->next(); after; after = after->next()) {
924953
if (Token::Match(after, "%name%|::|&|*|&&"))
925954
continue;
@@ -1014,6 +1043,9 @@ void Tokenizer::simplifyTypedef()
10141043
if (indentlevel == 0 && tok->str() == "typedef") {
10151044
TypedefSimplifier ts(tok, typeNum);
10161045
if (!ts.fail() && numberOfTypedefs[ts.name()] == 1) {
1046+
if (mSettings->severity.isEnabled(Severity::portability) && ts.isInvalidConstFunctionType(typedefs))
1047+
reportError(tok->next(), Severity::portability, "invalidConstFunctionType",
1048+
"It is unspecified behavior to const qualify a function type.");
10171049
typedefs.emplace(ts.name(), ts);
10181050
if (!ts.isStructEtc())
10191051
tok = ts.endToken();

test/testsimplifytypedef.cpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class TestSimplifyTypedef : public TestFixture {
4242
private:
4343
// If there are unused templates, keep those
4444
const Settings settings0 = settingsBuilder().severity(Severity::style).checkUnusedTemplates().build();
45-
const Settings settings1 = settingsBuilder().checkUnusedTemplates().build();
45+
const Settings settings1 = settingsBuilder().severity(Severity::portability).checkUnusedTemplates().build();
4646
const Settings settings2 = settingsBuilder().severity(Severity::style).checkUnusedTemplates().build();
4747

4848
void run() override {
@@ -57,6 +57,9 @@ class TestSimplifyTypedef : public TestFixture {
5757
TEST_CASE(cstruct3);
5858
TEST_CASE(cstruct3);
5959
TEST_CASE(cstruct4);
60+
TEST_CASE(cfunction1);
61+
TEST_CASE(cfunction2);
62+
TEST_CASE(cfunction3);
6063
TEST_CASE(cfp1);
6164
TEST_CASE(cfp2);
6265
TEST_CASE(cfp4);
@@ -382,6 +385,26 @@ class TestSimplifyTypedef : public TestFixture {
382385
ASSERT_EQUALS("struct s { int a ; int b ; } ; struct s x { } ;", simplifyTypedefC(code));
383386
}
384387

388+
void cfunction1() {
389+
const char code[] = "typedef int callback(int);\n"
390+
"callback* cb;";
391+
ASSERT_EQUALS("int ( * cb ) ( int ) ;", simplifyTypedefC(code));
392+
}
393+
394+
void cfunction2() {
395+
const char code[] = "typedef int callback(int);\n"
396+
"typedef callback* callbackPtr;\n"
397+
"callbackPtr cb;";
398+
ASSERT_EQUALS("int ( * cb ) ( int ) ;", simplifyTypedefC(code));
399+
}
400+
401+
void cfunction3() {
402+
const char code[] = "typedef int f(int);\n"
403+
"typedef const f cf;\n";
404+
simplifyTypedefC(code);
405+
ASSERT_EQUALS("[file.c:2]: (portability) It is unspecified behavior to const qualify a function type.\n", errout.str());
406+
}
407+
385408
void cfp1() {
386409
const char code[] = "typedef void (*fp)(void * p);\n"
387410
"fp x;";
@@ -3532,7 +3555,7 @@ class TestSimplifyTypedef : public TestFixture {
35323555
"func7 f7;";
35333556

35343557
// The expected result..
3535-
const char expected[] = "; C f1 ( ) ; "
3558+
const char expected[] = "C f1 ( ) ; "
35363559
"C ( * f2 ) ( ) ; "
35373560
"C ( & f3 ) ( ) ; "
35383561
"C ( * f4 ) ( ) ; "
@@ -3561,7 +3584,7 @@ class TestSimplifyTypedef : public TestFixture {
35613584

35623585
// The expected result..
35633586
// C const -> const C
3564-
const char expected[] = "; const C f1 ( ) ; "
3587+
const char expected[] = "const C f1 ( ) ; "
35653588
"const C ( * f2 ) ( ) ; "
35663589
"const C ( & f3 ) ( ) ; "
35673590
"const C ( * f4 ) ( ) ; "
@@ -3589,7 +3612,7 @@ class TestSimplifyTypedef : public TestFixture {
35893612
"func7 f7;";
35903613

35913614
// The expected result..
3592-
const char expected[] = "; const C f1 ( ) ; "
3615+
const char expected[] = "const C f1 ( ) ; "
35933616
"const C ( * f2 ) ( ) ; "
35943617
"const C ( & f3 ) ( ) ; "
35953618
"const C ( * f4 ) ( ) ; "
@@ -3617,7 +3640,7 @@ class TestSimplifyTypedef : public TestFixture {
36173640
"func7 f7;";
36183641

36193642
// The expected result..
3620-
const char expected[] = "; C * f1 ( ) ; "
3643+
const char expected[] = "C * f1 ( ) ; "
36213644
"C * ( * f2 ) ( ) ; "
36223645
"C * ( & f3 ) ( ) ; "
36233646
"C * ( * f4 ) ( ) ; "
@@ -3645,7 +3668,7 @@ class TestSimplifyTypedef : public TestFixture {
36453668
"func7 f7;";
36463669

36473670
// The expected result..
3648-
const char expected[] = "; const C * f1 ( ) ; "
3671+
const char expected[] = "const C * f1 ( ) ; "
36493672
"const C * ( * f2 ) ( ) ; "
36503673
"const C * ( & f3 ) ( ) ; "
36513674
"const C * ( * f4 ) ( ) ; "
@@ -3674,7 +3697,7 @@ class TestSimplifyTypedef : public TestFixture {
36743697

36753698
// The expected result..
36763699
// C const -> const C
3677-
const char expected[] = "; const C * f1 ( ) ; "
3700+
const char expected[] = "const C * f1 ( ) ; "
36783701
"const C * ( * f2 ) ( ) ; "
36793702
"const C * ( & f3 ) ( ) ; "
36803703
"const C * ( * f4 ) ( ) ; "

test/testtokenize.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3599,7 +3599,7 @@ class TestTokenizer : public TestFixture {
35993599
ASSERT_EQUALS("unsigned int ( * f ) ( ) ;", tokenizeAndStringify("unsigned int (*f)();"));
36003600
ASSERT_EQUALS("unsigned int * ( * f ) ( ) ;", tokenizeAndStringify("unsigned int * (*f)();"));
36013601
ASSERT_EQUALS("void ( * f [ 2 ] ) ( ) ;", tokenizeAndStringify("void (*f[2])();"));
3602-
TODO_ASSERT_EQUALS("void ( * f [ 2 ] ) ( ) ;", "void ( * f ) ( void ) [ 2 ] ;", tokenizeAndStringify("typedef void func_t(void); func_t *f[2];"));
3602+
ASSERT_EQUALS("void ( * f [ 2 ] ) ( void ) ;", tokenizeAndStringify("typedef void func_t(void); func_t *f[2];"));
36033603
}
36043604

36053605
void simplifyFunctionPointers2() {

0 commit comments

Comments
 (0)