Fixed #1275 (Cppcheck hangs when analysing the code 'typedef struct { } A, *B, **C;')

This commit is contained in:
Robert Reif 2010-01-17 08:16:17 +01:00 committed by Daniel Marjamäki
parent 2851e76414
commit 70dbb8ba17
2 changed files with 329 additions and 218 deletions

View File

@ -447,131 +447,150 @@ void Tokenizer::simplifyTypedef()
const char *type2 = 0;
const char *typeName = 0;
bool pointer = false;
bool toPointer = false;
Token *start = 0;
Token *end = 0;
Token *num = 0;
Token *typeDef = tok;
if (Token::Match(tok->next(), "%type% <") ||
Token::Match(tok->next(), "%type% %type% <") ||
Token::Match(tok->next(), "%type% :: %type% <") ||
Token::Match(tok->next(), "%type% *| %type% ;|,") ||
Token::Match(tok->next(), "%type% %type% *| %type% ;|,") ||
Token::Match(tok->next(), "%type% *| %type% [ %num% ] ;|,") ||
Token::Match(tok->next(), "%type% %type% *| %type% [ %num% ] ;|,"))
{
if ((tok->tokAt(2)->str() == "<") ||
(tok->tokAt(4) && (tok->tokAt(4)->str() == "<")))
Token::Match(tok->next(), "%type% %type% :: %type% <"))
{
// template
int level = 1;
start = tok->next();
if (tok->tokAt(2)->str() == "<")
end = tok->tokAt(3);
else
else if (tok->tokAt(3)->str() == "<")
end = tok->tokAt(4);
else if (tok->tokAt(4)->str() == "<")
end = tok->tokAt(5);
else
end = tok->tokAt(6);
int paren = 0;
for (; end ; end = end->next())
{
if (end->str() == ">")
{
if (paren == 0)
{
level--;
if (level == 0)
break;
}
if (end->str() == "<")
}
else if (end->str() == "<")
{
if (paren == 0)
level++;
}
else if (end->str() == "(")
paren++;
else if (end->str() == ")")
paren--;
}
while (end && end->next() && Token::Match(end->next(), ":: %type%"))
end = end->tokAt(2);
if (end && end->next() && Token::Match(end->next(), "%type% ;|,"))
if (end && end->next() && end->next()->str() == "*")
{
pointer = true;
end = end->next();
}
if (end && end->next() && end->next()->str() == "*")
{
toPointer = true;
end = end->next();
}
if (end && end->next() && (Token::Match(end->next(), "%type% ;|,") || Token::Match(end->next(), "%type% [ %num% ] ;|,")))
{
typeName = end->strAt(1);
if (end->tokAt(2)->str() == "[")
{
num = end->tokAt(3);
tok = end->tokAt(5);
}
else
tok = end->tokAt(2);
}
else
{
// unhandled template typedef, skip it and continue
continue;
}
else if ((tok->tokAt(3) && tok->tokAt(3)->str() == "[") ||
(tok->tokAt(4) && tok->tokAt(4)->str() == "[") ||
(tok->tokAt(5) && tok->tokAt(5)->str() == "["))
}
else if (Token::Match(tok->next(), "%type% *| *| %type% [ %num% ] ;|,") ||
Token::Match(tok->next(), "%type% %type% *| *| %type% [ %num% ] ;|,"))
{
// array
int offset = 2;
type1 = tok->strAt(1);
if ((tok->tokAt(4) && tok->tokAt(4)->str() == "[" && tok->tokAt(2)->str() != "*") ||
(tok->tokAt(5) && tok->tokAt(5)->str() == "["))
if (tok->tokAt(2)->str() != "*" && tok->tokAt(3)->str() != "[")
{
type2 = tok->strAt(2);
pointer = (tok->tokAt(3)->str() == "*");
offset++;
}
if (pointer)
{
typeName = tok->strAt(4);
num = tok->tokAt(6);
tok = tok->tokAt(8);
}
else
{
typeName = tok->strAt(3);
num = tok->tokAt(5);
tok = tok->tokAt(7);
}
}
else
{
pointer = (tok->tokAt(2)->str() == "*");
if (pointer)
{
typeName = tok->strAt(3);
num = tok->tokAt(5);
tok = tok->tokAt(7);
}
else
{
typeName = tok->strAt(2);
num = tok->tokAt(4);
tok = tok->tokAt(6);
}
}
}
else if (tok->tokAt(3)->str() == ";" ||
tok->tokAt(3)->str() == ",")
{
type1 = tok->strAt(1);
type2 = 0;
typeName = tok->strAt(2);
tok = tok->tokAt(3);
}
else if (tok->tokAt(2)->str() == "*")
if (tok->tokAt(offset) && (tok->tokAt(offset)->str() == "*"))
{
pointer = true;
type1 = tok->strAt(1);
type2 = 0;
typeName = tok->strAt(3);
tok = tok->tokAt(4);
offset++;
}
else
{
pointer = (tok->tokAt(3)->str() == "*");
if (tok->tokAt(offset) && (tok->tokAt(offset)->str() == "*"))
{
toPointer = true;
offset++;
}
typeName = tok->strAt(offset);
num = tok->tokAt(offset + 2);
tok = tok->tokAt(offset + 4);
}
else if (Token::Match(tok->next(), "%type% *| *| %type% ;|,") ||
Token::Match(tok->next(), "%type% %type% *| *| %type% ;|,"))
{
int offset = 2;
type1 = tok->strAt(1);
if (tok->tokAt(2)->str() != "*" && (tok->tokAt(3)->str() != ";" && tok->tokAt(3)->str() != ","))
{
type2 = tok->strAt(2);
offset++;
}
if (pointer)
if (tok->tokAt(offset) && (tok->tokAt(offset)->str() == "*"))
{
typeName = tok->strAt(4);
tok = tok->tokAt(5);
pointer = true;
offset++;
}
if (tok->tokAt(offset) && (tok->tokAt(offset)->str() == "*"))
{
toPointer = true;
offset++;
}
typeName = tok->strAt(offset++);
tok = tok->tokAt(offset);
}
else
{
typeName = tok->strAt(3);
tok = tok->tokAt(4);
}
// unhandled typedef, skip it and continue
continue;
}
bool done = false;
bool ok = true;
while (!done)
{
@ -661,12 +680,18 @@ void Tokenizer::simplifyTypedef()
tok2->insertToken(type2);
tok2 = tok2->next();
}
}
if (pointer)
{
tok2->insertToken("*");
tok2 = tok2->next();
}
if (toPointer)
{
tok2->insertToken("*");
tok2 = tok2->next();
}
if (num)
{
tok2 = tok2->next();
@ -679,7 +704,6 @@ void Tokenizer::simplifyTypedef()
tok2 = tok2->next();
Token::createMutualLinks(tok2, tok3);
}
}
simplifyType = false;
}
@ -687,15 +711,30 @@ void Tokenizer::simplifyTypedef()
if (tok->str() == ";")
done = true;
else
else if (tok->str() == ",")
{
if (Token::Match(tok->next(), "*| %type% ;|,") ||
Token::Match(tok->next(), "*| %type% [ %num% ] ;|,"))
if (Token::Match(tok->next(), "*| *| %type% ;|,") ||
Token::Match(tok->next(), "*| *| %type% [ %num% ] ;|,"))
{
num = 0;
pointer = (tok->tokAt(1)->str() == "*");
toPointer = (tok->tokAt(2)->str() == "*");
if (pointer)
{
if (toPointer)
{
typeName = tok->strAt(3);
if (tok->tokAt(4)->str() == "[")
{
num = tok->tokAt(5);
tok = tok->tokAt(7);
}
else
tok = tok->tokAt(4);
}
else
{
typeName = tok->strAt(2);
@ -707,6 +746,7 @@ void Tokenizer::simplifyTypedef()
else
tok = tok->tokAt(3);
}
}
else
{
typeName = tok->strAt(1);
@ -720,9 +760,23 @@ void Tokenizer::simplifyTypedef()
tok = tok->tokAt(2);
}
}
else
{
// we encountered a typedef we don't support yet so just continue
done = true;
ok = false;
}
}
else
{
// something is really wrong (internal error)
done = true;
ok = false;
}
}
if (ok)
{
// remove typedef but leave ;
while (typeDef->next() && typeDef->next() != tok)
typeDef->deleteNext();

View File

@ -153,6 +153,7 @@ private:
TEST_CASE(simplifyTypedef16);
TEST_CASE(simplifyTypedef17);
TEST_CASE(simplifyTypedef18); // typedef vector<int[4]> a;
TEST_CASE(simplifyTypedef19);
TEST_CASE(reverseArraySyntax)
TEST_CASE(simplify_numeric_condition)
@ -2555,6 +2556,62 @@ private:
ASSERT_EQUALS(true, tokenizer.validate());
}
void simplifyTypedef19()
{
{
// ticket #1275
const char code[] = "typedef struct {} A, *B, **C;\n"
"A a;\n"
"B b;\n"
"C c;";
const char expected[] =
"struct A { } ; ; "
"struct A a ; "
"struct A * b ; "
"struct A * * c ;";
ASSERT_EQUALS(expected, tok(code, false));
}
{
// This doesn't work yet.
// The first name gets substituted successfully.
// The second doesn't so the typedef is left alone.
// The variable declaration simplification code then splits the typedef into two.
const char code[] = "typedef struct {} A, ***B;\n"
"A a;\n"
"B b;";
const char expected[] =
"struct A { } ; typedef struct A A ; typedef struct A * * * B ; "
"struct A a ; "
"B b ;";
const char todo[] =
"struct A { } ; ; "
"struct A a ; "
"struct A * * * b ;";
ASSERT_EQUALS(expected, tok(code, false));
TODO_ASSERT_EQUALS(todo, tok(code, false));
}
{
const char code[] = "typedef struct {} **A, *B, C;\n"
"A a;\n"
"B b;\n"
"C c;";
const char expected[] =
"struct Unnamed2 { } ; ; "
"struct Unnamed2 * * a ; "
"struct Unnamed2 * b ; "
"struct Unnamed2 c ;";
ASSERT_EQUALS(expected, tok(code, false));
}
}
void reverseArraySyntax()
{
ASSERT_EQUALS("a [ 13 ]", tok("13[a]"));