From 418c2e51a0f156b9f7057934bffa83472c52cd8c Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Fri, 28 Nov 2014 17:44:36 +0100 Subject: [PATCH] Fixed #3314 (cppcheck incorrectly reporting Syntax error.) --- lib/tokenize.cpp | 39 +++++++++------- test/testgarbage.cpp | 7 --- test/testsimplifytypedef.cpp | 87 ++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+), 22 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index f56a0c949..9cab48bd3 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -619,13 +619,34 @@ void Tokenizer::simplifyTypedef() Token *namespaceEnd = nullptr; // check for invalid input - if (!tok->next()) { + if (!tokOffset) { syntaxError(tok); return; } - if (tok->next()->str() == "::" || Token::Match(tok->next(), "%type%")) { - typeStart = tok->next(); + if (tokOffset->str() == "::") { + 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%") || (tokOffset->next() && tokOffset->next()->isStandardType())) @@ -738,18 +759,6 @@ void Tokenizer::simplifyTypedef() 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 else if (Token::Match(tokOffset, "( * %var% ) (")) { // name token wasn't a name, it was part of the type diff --git a/test/testgarbage.cpp b/test/testgarbage.cpp index ce7c67a6e..c926e82ee 100644 --- a/test/testgarbage.cpp +++ b/test/testgarbage.cpp @@ -117,13 +117,6 @@ private: const char code[] ="enum ABC { A,B, typedef enum { C } };"; 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 diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 1652aae0b..61ab73849 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -154,6 +154,7 @@ private: TEST_CASE(simplifyTypedefFunction6); TEST_CASE(simplifyTypedefFunction7); TEST_CASE(simplifyTypedefFunction8); + TEST_CASE(simplifyTypedefFunction9); 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 } + 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) const char code[] = "typedef struct { int x; } xyz;;\n" "void f(){\n"