Fixed #11716 (simplifyTypedef: function with const should be handled better) (#5054)

This commit is contained in:
Daniel Marjamäki 2023-05-12 20:39:08 +02:00 committed by GitHub
parent aa6df06f43
commit 2b74a2084e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 63 additions and 8 deletions

View File

@ -695,6 +695,15 @@ namespace {
mRangeAfterVar.second = mEndToken; mRangeAfterVar.second = mEndToken;
return; 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 // TODO: handle all typedefs
if ((false)) if ((false))
@ -710,6 +719,15 @@ namespace {
return mUsed; 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 { bool fail() const {
return mFail; return mFail;
} }
@ -823,6 +841,15 @@ namespace {
Token *after = tok3; Token *after = tok3;
while (Token::Match(after, "%name%|*|&|&&|::")) while (Token::Match(after, "%name%|*|&|&&|::"))
after = after->next(); 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; bool useAfterVarRange = true;
if (Token::simpleMatch(mRangeAfterVar.first, "[")) { if (Token::simpleMatch(mRangeAfterVar.first, "[")) {
@ -920,6 +947,8 @@ namespace {
return true; return true;
if (Token::Match(tok->previous(), "; %name% ;")) if (Token::Match(tok->previous(), "; %name% ;"))
return false; return false;
if (Token::Match(tok->previous(), "<|, %name% * ,|>"))
return true;
for (const Token* after = tok->next(); after; after = after->next()) { for (const Token* after = tok->next(); after; after = after->next()) {
if (Token::Match(after, "%name%|::|&|*|&&")) if (Token::Match(after, "%name%|::|&|*|&&"))
continue; continue;
@ -1014,6 +1043,9 @@ void Tokenizer::simplifyTypedef()
if (indentlevel == 0 && tok->str() == "typedef") { if (indentlevel == 0 && tok->str() == "typedef") {
TypedefSimplifier ts(tok, typeNum); TypedefSimplifier ts(tok, typeNum);
if (!ts.fail() && numberOfTypedefs[ts.name()] == 1) { 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); typedefs.emplace(ts.name(), ts);
if (!ts.isStructEtc()) if (!ts.isStructEtc())
tok = ts.endToken(); tok = ts.endToken();

View File

@ -42,7 +42,7 @@ public:
private: private:
// If there are unused templates, keep those // If there are unused templates, keep those
const Settings settings0 = settingsBuilder().severity(Severity::style).checkUnusedTemplates().build(); 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(); const Settings settings2 = settingsBuilder().severity(Severity::style).checkUnusedTemplates().build();
void run() override { void run() override {
@ -57,6 +57,9 @@ private:
TEST_CASE(cstruct3); TEST_CASE(cstruct3);
TEST_CASE(cstruct3); TEST_CASE(cstruct3);
TEST_CASE(cstruct4); TEST_CASE(cstruct4);
TEST_CASE(cfunction1);
TEST_CASE(cfunction2);
TEST_CASE(cfunction3);
TEST_CASE(cfp1); TEST_CASE(cfp1);
TEST_CASE(cfp2); TEST_CASE(cfp2);
TEST_CASE(cfp4); TEST_CASE(cfp4);
@ -382,6 +385,26 @@ private:
ASSERT_EQUALS("struct s { int a ; int b ; } ; struct s x { } ;", simplifyTypedefC(code)); 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() { void cfp1() {
const char code[] = "typedef void (*fp)(void * p);\n" const char code[] = "typedef void (*fp)(void * p);\n"
"fp x;"; "fp x;";
@ -3532,7 +3555,7 @@ private:
"func7 f7;"; "func7 f7;";
// The expected result.. // The expected result..
const char expected[] = "; C f1 ( ) ; " const char expected[] = "C f1 ( ) ; "
"C ( * f2 ) ( ) ; " "C ( * f2 ) ( ) ; "
"C ( & f3 ) ( ) ; " "C ( & f3 ) ( ) ; "
"C ( * f4 ) ( ) ; " "C ( * f4 ) ( ) ; "
@ -3561,7 +3584,7 @@ private:
// The expected result.. // The expected result..
// C const -> const C // C const -> const C
const char expected[] = "; const C f1 ( ) ; " const char expected[] = "const C f1 ( ) ; "
"const C ( * f2 ) ( ) ; " "const C ( * f2 ) ( ) ; "
"const C ( & f3 ) ( ) ; " "const C ( & f3 ) ( ) ; "
"const C ( * f4 ) ( ) ; " "const C ( * f4 ) ( ) ; "
@ -3589,7 +3612,7 @@ private:
"func7 f7;"; "func7 f7;";
// The expected result.. // The expected result..
const char expected[] = "; const C f1 ( ) ; " const char expected[] = "const C f1 ( ) ; "
"const C ( * f2 ) ( ) ; " "const C ( * f2 ) ( ) ; "
"const C ( & f3 ) ( ) ; " "const C ( & f3 ) ( ) ; "
"const C ( * f4 ) ( ) ; " "const C ( * f4 ) ( ) ; "
@ -3617,7 +3640,7 @@ private:
"func7 f7;"; "func7 f7;";
// The expected result.. // The expected result..
const char expected[] = "; C * f1 ( ) ; " const char expected[] = "C * f1 ( ) ; "
"C * ( * f2 ) ( ) ; " "C * ( * f2 ) ( ) ; "
"C * ( & f3 ) ( ) ; " "C * ( & f3 ) ( ) ; "
"C * ( * f4 ) ( ) ; " "C * ( * f4 ) ( ) ; "
@ -3645,7 +3668,7 @@ private:
"func7 f7;"; "func7 f7;";
// The expected result.. // The expected result..
const char expected[] = "; const C * f1 ( ) ; " const char expected[] = "const C * f1 ( ) ; "
"const C * ( * f2 ) ( ) ; " "const C * ( * f2 ) ( ) ; "
"const C * ( & f3 ) ( ) ; " "const C * ( & f3 ) ( ) ; "
"const C * ( * f4 ) ( ) ; " "const C * ( * f4 ) ( ) ; "
@ -3674,7 +3697,7 @@ private:
// The expected result.. // The expected result..
// C const -> const C // C const -> const C
const char expected[] = "; const C * f1 ( ) ; " const char expected[] = "const C * f1 ( ) ; "
"const C * ( * f2 ) ( ) ; " "const C * ( * f2 ) ( ) ; "
"const C * ( & f3 ) ( ) ; " "const C * ( & f3 ) ( ) ; "
"const C * ( * f4 ) ( ) ; " "const C * ( * f4 ) ( ) ; "

View File

@ -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("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])();")); 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() { void simplifyFunctionPointers2() {