Fix #761 (Tokenizer: typedef inside class is incorrectly simplified)

http://sourceforge.net/apps/trac/cppcheck/ticket/761
This commit is contained in:
Reijo Tomperi 2009-09-30 14:35:00 +03:00
parent bb1a9a07e4
commit 7852d38f54
3 changed files with 155 additions and 40 deletions

View File

@ -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())

View File

@ -186,6 +186,16 @@ private:
*/
void simplifyDoWhileAddBraces();
/**
* typedef A mytype;
* mytype c;
*
* Becomes:
* typedef A mytype;
* A c;
*/
void simplifyTypedef();
/**
* Simplify casts
*/

View File

@ -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)