Fixed #3314 (cppcheck incorrectly reporting Syntax error.)

This commit is contained in:
Robert Reif 2014-11-28 17:44:36 +01:00 committed by Daniel Marjamäki
parent 0dad8b64e8
commit 418c2e51a0
3 changed files with 111 additions and 22 deletions

View File

@ -619,13 +619,34 @@ void Tokenizer::simplifyTypedef()
Token *namespaceEnd = nullptr; Token *namespaceEnd = nullptr;
// check for invalid input // check for invalid input
if (!tok->next()) { if (!tokOffset) {
syntaxError(tok); syntaxError(tok);
return; return;
} }
if (tok->next()->str() == "::" || Token::Match(tok->next(), "%type%")) { if (tokOffset->str() == "::") {
typeStart = tok->next(); typeStart = tokOffset;
tokOffset = tokOffset->next();
while (Token::Match(tokOffset, "%type% ::"))
tokOffset = tokOffset->tokAt(2);
typeEnd = tokOffset;
if (Token::Match(tokOffset, "%type%"))
tokOffset = tokOffset->next();
} else if (Token::Match(tokOffset, "%type% ::")) {
typeStart = tokOffset;
while (Token::Match(tokOffset, "%type% ::"))
tokOffset = tokOffset->tokAt(2);
typeEnd = tokOffset;
if (Token::Match(tokOffset, "%type%"))
tokOffset = tokOffset->next();
} else if (Token::Match(tokOffset, "%type%")) {
typeStart = tokOffset;
while (Token::Match(tokOffset, "const|signed|unsigned|struct|enum %type%") || while (Token::Match(tokOffset, "const|signed|unsigned|struct|enum %type%") ||
(tokOffset->next() && tokOffset->next()->isStandardType())) (tokOffset->next() && tokOffset->next()->isStandardType()))
@ -738,18 +759,6 @@ void Tokenizer::simplifyTypedef()
continue; continue;
} }
// unhandled function pointer, skip it and continue
// TODO: handle such typedefs. See ticket #3314
else if (Token::Match(tokOffset, "( %type% ::") &&
Token::Match(tokOffset->link()->tokAt(-3), ":: * %var% ) (")) {
unsupportedTypedef(typeDef);
tok = deleteInvalidTypedef(typeDef);
if (tok == list.front())
//now the next token to process is 'tok', not 'tok->next()';
goback = true;
continue;
}
// function pointer // function pointer
else if (Token::Match(tokOffset, "( * %var% ) (")) { else if (Token::Match(tokOffset, "( * %var% ) (")) {
// name token wasn't a name, it was part of the type // name token wasn't a name, it was part of the type

View File

@ -117,13 +117,6 @@ private:
const char code[] ="enum ABC { A,B, typedef enum { C } };"; const char code[] ="enum ABC { A,B, typedef enum { C } };";
ASSERT_THROW(checkCode(code), InternalError); ASSERT_THROW(checkCode(code), InternalError);
} }
{
// #3314 - don't report syntax error.
const char code[] ="struct A { typedef B::C (A::*f)(); };";
checkCode(code);
ASSERT_EQUALS("[test.cpp:1]: (debug) Failed to parse 'typedef B :: C ( A :: * f ) ( ) ;'. The checking continues anyway.\n", errout.str());
}
} }
void wrong_syntax2() { // #3504 void wrong_syntax2() { // #3504

View File

@ -154,6 +154,7 @@ private:
TEST_CASE(simplifyTypedefFunction6); TEST_CASE(simplifyTypedefFunction6);
TEST_CASE(simplifyTypedefFunction7); TEST_CASE(simplifyTypedefFunction7);
TEST_CASE(simplifyTypedefFunction8); TEST_CASE(simplifyTypedefFunction8);
TEST_CASE(simplifyTypedefFunction9);
TEST_CASE(simplifyTypedefShadow); // #4445 - shadow variable TEST_CASE(simplifyTypedefShadow); // #4445 - shadow variable
} }
@ -3033,6 +3034,92 @@ private:
TODO_ASSERT_EQUALS("", "[test.cpp:2]: (debug) Function::addArguments found argument 'int' with varid 0.\n", errout.str()); // make sure that there is no internal error TODO_ASSERT_EQUALS("", "[test.cpp:2]: (debug) Function::addArguments found argument 'int' with varid 0.\n", errout.str()); // make sure that there is no internal error
} }
void simplifyTypedefFunction9() {
{
const char code[] = "typedef ::C (::C::* func1)();\n"
"typedef ::C (::C::* func2)() const;\n"
"typedef ::C (::C::* func3)() volatile;\n"
"typedef ::C (::C::* func4)() const volatile;\n"
"func1 f1;\n"
"func2 f2;\n"
"func3 f3;\n"
"func4 f4;";
// The expected result..
const std::string expected(":: C ( :: C :: * f1 ) ( ) ; "
":: C ( :: C :: * f2 ) ( ) const ; "
":: C ( :: C :: * f3 ) ( ) ; "
":: C ( :: C :: * f4 ) ( ) const ;");
ASSERT_EQUALS(expected, tok(code));
checkSimplifyTypedef(code);
ASSERT_EQUALS("", errout.str());
}
{
const char code[] = "typedef B::C (B::C::* func1)();\n"
"typedef B::C (B::C::* func2)() const;\n"
"typedef B::C (B::C::* func3)() volatile;\n"
"typedef B::C (B::C::* func4)() const volatile;\n"
"func1 f1;\n"
"func2 f2;\n"
"func3 f3;\n"
"func4 f4;";
// The expected result..
const std::string expected("B :: C * f1 ; "
"B :: C ( B :: C :: * f2 ) ( ) const ; "
"B :: C * f3 ; "
"B :: C ( B :: C :: * f4 ) ( ) const ;");
ASSERT_EQUALS(expected, tok(code));
checkSimplifyTypedef(code);
ASSERT_EQUALS("", errout.str());
}
{
const char code[] = "typedef ::B::C (::B::C::* func1)();\n"
"typedef ::B::C (::B::C::* func2)() const;\n"
"typedef ::B::C (::B::C::* func3)() volatile;\n"
"typedef ::B::C (::B::C::* func4)() const volatile;\n"
"func1 f1;\n"
"func2 f2;\n"
"func3 f3;\n"
"func4 f4;";
// The expected result..
const std::string expected(":: B :: C ( :: B :: C :: * f1 ) ( ) ; "
":: B :: C ( :: B :: C :: * f2 ) ( ) const ; "
":: B :: C ( :: B :: C :: * f3 ) ( ) ; "
":: B :: C ( :: B :: C :: * f4 ) ( ) const ;");
ASSERT_EQUALS(expected, tok(code));
checkSimplifyTypedef(code);
ASSERT_EQUALS("", errout.str());
}
{
const char code[] = "typedef A::B::C (A::B::C::* func1)();\n"
"typedef A::B::C (A::B::C::* func2)() const;\n"
"typedef A::B::C (A::B::C::* func3)() volatile;\n"
"typedef A::B::C (A::B::C::* func4)() const volatile;\n"
"func1 f1;\n"
"func2 f2;\n"
"func3 f3;\n"
"func4 f4;";
// The expected result..
const std::string expected("A :: B :: C * f1 ; "
"A :: B :: C ( A :: B :: C :: * f2 ) ( ) const ; "
"A :: B :: C * f3 ; "
"A :: B :: C ( A :: B :: C :: * f4 ) ( ) const ;");
ASSERT_EQUALS(expected, tok(code));
checkSimplifyTypedef(code);
ASSERT_EQUALS("", errout.str());
}
}
void simplifyTypedefShadow() { // shadow variable (#4445) void simplifyTypedefShadow() { // shadow variable (#4445)
const char code[] = "typedef struct { int x; } xyz;;\n" const char code[] = "typedef struct { int x; } xyz;;\n"
"void f(){\n" "void f(){\n"