From 7852d38f540339a19143a31a9c5dfbca21ce37f0 Mon Sep 17 00:00:00 2001 From: Reijo Tomperi Date: Wed, 30 Sep 2009 14:35:00 +0300 Subject: [PATCH] Fix #761 (Tokenizer: typedef inside class is incorrectly simplified) http://sourceforge.net/apps/trac/cppcheck/ticket/761 --- src/tokenize.cpp | 145 +++++++++++++++++++++++++++--------- src/tokenize.h | 10 +++ test/testsimplifytokens.cpp | 40 ++++++++-- 3 files changed, 155 insertions(+), 40 deletions(-) diff --git a/src/tokenize.cpp b/src/tokenize.cpp index ac8558c9a..bba2f72a5 100644 --- a/src/tokenize.cpp +++ b/src/tokenize.cpp @@ -341,6 +341,116 @@ void Tokenizer::createTokens(std::istream &code) } +void Tokenizer::simplifyTypedef() +{ + std::string className; + int classLevel = 0; + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (Token::Match(tok, "class %any%")) + { + className = tok->next()->str(); + classLevel = 0; + continue; + } + else if (tok->str() == "}") + { + --classLevel; + if (classLevel < 0) + className = ""; + + continue; + } + else if (tok->str() == "{") + { + ++classLevel; + continue; + } + else if (tok->str() != "typedef") + continue; + + const char *type1 = 0; + const char *type2 = 0; + const char *typeName = 0; + + if (Token::Match(tok->next(), "%type% %type% ;") || + Token::Match(tok->next(), "%type% %type% %type% ;")) + { + if (tok->tokAt(3)->str() == ";") + { + type1 = tok->strAt(1); + type2 = 0; + typeName = tok->strAt(2); + tok = tok->tokAt(3); + } + else + { + type1 = tok->strAt(1); + type2 = tok->strAt(2); + typeName = tok->strAt(3); + tok = tok->tokAt(4); + } + + const std::string pattern = className + " :: " + typeName; + int level = 0; + bool inScope = true; + + bool exitThisScope = false; + int exitScope = 0; + bool simplifyType = false; + for (Token *tok2 = tok; tok2; tok2 = tok2->next()) + { + if (tok2->str() == "}") + { + --level; + if (level < 0) + inScope = false; + + if (exitThisScope) + { + if (level < exitScope) + exitThisScope = false; + } + } + else if (tok2->str() == "{") + ++level; + else if (Token::Match(tok2, pattern.c_str())) + { + tok2->deleteNext(); + tok2->deleteNext(); + simplifyType = true; + } + else if (inScope && !exitThisScope && tok2->str() == typeName) + { + if (Token::Match(tok2->tokAt(-2), "!!typedef") && + Token::Match(tok2->tokAt(-3), "!!typedef")) + { + simplifyType = true; + } + else + { + // Typedef with the same name. + exitThisScope = true; + exitScope = level; + } + } + + if (simplifyType) + { + tok2->str(type1); + if (type2) + { + tok2->insertToken(type2); + tok2 = tok2->next(); + } + + simplifyType = false; + } + } + } + } +} + bool Tokenizer::tokenize(std::istream &code, const char FileName[]) { // The "_files" vector remembers what files have been tokenized.. @@ -412,40 +522,7 @@ bool Tokenizer::tokenize(std::istream &code, const char FileName[]) } // typedef.. - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() != "typedef") - continue; - - if (Token::Match(tok->next(), "%type% %type% ;")) - { - const char *type1 = tok->strAt(1); - const char *type2 = tok->strAt(2); - tok = tok->tokAt(3); - for (Token *tok2 = tok; tok2; tok2 = tok2->next()) - { - if (tok2->str() == type2) - tok2->str(type1); - } - } - - else if (Token::Match(tok->next(), "%type% %type% %type% ;")) - { - const char *type1 = tok->strAt(1); - const char *type2 = tok->strAt(2); - const char *type3 = tok->strAt(3); - tok = tok->tokAt(4); - for (Token *tok2 = tok; tok2; tok2 = tok2->next()) - { - if (tok2->str() == type3) - { - tok2->str(type1); - tok2->insertToken(type2); - tok2 = tok2->next(); - } - } - } - } + simplifyTypedef(); // Remove __asm.. for (Token *tok = _tokens; tok; tok = tok->next()) diff --git a/src/tokenize.h b/src/tokenize.h index 23366fb33..5c02cafbc 100644 --- a/src/tokenize.h +++ b/src/tokenize.h @@ -186,6 +186,16 @@ private: */ void simplifyDoWhileAddBraces(); + /** + * typedef A mytype; + * mytype c; + * + * Becomes: + * typedef A mytype; + * A c; + */ + void simplifyTypedef(); + /** * Simplify casts */ diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 6968e16fb..fcb8ffdb2 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -122,14 +122,18 @@ private: TEST_CASE(simplifyTypedef) TEST_CASE(simplifyTypedef2) TEST_CASE(simplifyTypedef3) + TEST_CASE(simplifyTypedef4) } - std::string tok(const char code[]) + std::string tok(const char code[], bool simplify = true) { std::istringstream istr(code); Tokenizer tokenizer; tokenizer.tokenize(istr, "test.cpp"); - tokenizer.simplifyTokenList(); + + if (simplify) + tokenizer.simplifyTokenList(); + std::string ret; for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) { @@ -1639,9 +1643,9 @@ private: "{ " "A a ; " "a . foo ( ) ; " - "wchar_t c = 0 ; " + "wchar_t c ; c = 0 ; " "}"; - TODO_ASSERT_EQUALS(expected, tok(code)); + ASSERT_EQUALS(expected, tok(code)); } void simplifyTypedef2() @@ -1664,7 +1668,7 @@ private: "typedef wchar_t duplicate ; " "wchar_t foo ( ) { wchar_t b ; return b ; } " "} ;"; - TODO_ASSERT_EQUALS(expected, tok(code)); + ASSERT_EQUALS(expected, tok(code)); } void simplifyTypedef3() @@ -1695,8 +1699,32 @@ private: "{ " "A b ; " "}"; - TODO_ASSERT_EQUALS(expected, tok(code)); + ASSERT_EQUALS(expected, tok(code)); } + + void simplifyTypedef4() + { + const char code[] = "typedef int s32;\n" + "typedef unsigned int u32;\n" + "void f()\n" + "{\n" + " s32 ivar = -2;\n" + " u32 uvar = 2;\n" + " return uvar / ivar;\n" + "}\n"; + + const std::string expected = + "typedef int s32 ; " + "typedef unsigned int u32 ; " + "void f ( ) " + "{ " + "int ivar ; ivar = -2 ; " + "unsigned int uvar ; uvar = 2 ; " + "return uvar / ivar ; " + "}"; + ASSERT_EQUALS(expected, tok(code, false)); + } + }; REGISTER_TEST(TestSimplifyTokens)