diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 14e5831ad..8dd6c585e 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -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)) @@ -710,6 +719,15 @@ namespace { return mUsed; } + bool isInvalidConstFunctionType(const std::map& 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; } @@ -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, "[")) { @@ -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; @@ -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(); diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 6a7fc9a91..52f3ca5c4 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -42,7 +42,7 @@ public: 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 { @@ -57,6 +57,9 @@ private: 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); @@ -382,6 +385,26 @@ private: 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;"; @@ -3532,7 +3555,7 @@ private: "func7 f7;"; // The expected result.. - const char expected[] = "; C f1 ( ) ; " + const char expected[] = "C f1 ( ) ; " "C ( * f2 ) ( ) ; " "C ( & f3 ) ( ) ; " "C ( * f4 ) ( ) ; " @@ -3561,7 +3584,7 @@ private: // 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 ) ( ) ; " @@ -3589,7 +3612,7 @@ private: "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 ) ( ) ; " @@ -3617,7 +3640,7 @@ private: "func7 f7;"; // The expected result.. - const char expected[] = "; C * f1 ( ) ; " + const char expected[] = "C * f1 ( ) ; " "C * ( * f2 ) ( ) ; " "C * ( & f3 ) ( ) ; " "C * ( * f4 ) ( ) ; " @@ -3645,7 +3668,7 @@ private: "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 ) ( ) ; " @@ -3674,7 +3697,7 @@ private: // 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 ) ( ) ; " diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 488ba5549..1bf9ed682 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -3599,7 +3599,7 @@ private: 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() {