Fixed #498 (Tokenizer: simplify 'goto')

This commit is contained in:
Daniel Marjamäki 2009-08-24 23:10:12 +02:00
parent 0c479b8c9f
commit c25e1963b1
5 changed files with 178 additions and 10 deletions

View File

@ -1139,6 +1139,8 @@ void Tokenizer::simplifyTokenList()
{
simplifyNamespaces();
simplifyGoto();
// Combine wide strings
for (Token *tok = _tokens; tok; tok = tok->next())
{
@ -3111,6 +3113,119 @@ bool Tokenizer::simplifyCalculations()
void Tokenizer::simplifyGoto()
{
std::list<Token *> gotos;
unsigned int indentlevel = 0;
Token *beginfunction = 0;
for (Token *tok = _tokens; tok; tok = tok->next())
{
if (tok->str() == "{")
++indentlevel;
else if (tok->str() == "}")
{
if (indentlevel == 0)
break; // break out - it seems the code is wrong
--indentlevel;
if (indentlevel == 0)
{
gotos.clear();
beginfunction = 0;
}
}
else if (indentlevel == 0 && Token::Match(tok, ") const| {"))
{
gotos.clear();
beginfunction = tok;
}
else if (Token::Match(tok, "goto %var% ;"))
gotos.push_back(tok);
else if (indentlevel == 1 && Token::Match(tok, "%var% :"))
{
// Is this label at the end..
bool end = false;
for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next())
{
if (tok2->str() == "}")
{
end = true;
break;
}
if (tok2->str() == "{" || Token::Match(tok2, "%var% :"))
{
break;
}
}
if (!end)
continue;
const std::string name(tok->str());
tok->deleteThis();
tok->deleteThis();
// This label is at the end of the function.. replace all matching goto statements..
for (std::list<Token *>::iterator it = gotos.begin(); it != gotos.end(); ++it)
{
Token *token = *it;
if (token->next()->str() == name)
{
// Delete the "goto name;"
token = token->previous();
token->deleteNext();
token->deleteNext();
token->deleteNext();
const bool endpar(token->str() == ")");
if (endpar)
{
token->insertToken("{");
token = token->next();
}
// Insert the statements..
bool ret = false;
for (const Token *tok2 = tok; tok2; tok2 = tok2->next())
{
if (tok2->str() == "}")
break;
if (tok2->str() == "return")
ret = true;
token->insertToken(tok2->str().c_str());
token = token->next();
}
if (!ret)
{
token->insertToken("return");
token = token->next();
token->insertToken(";");
token = token->next();
}
if (endpar)
{
token->insertToken("}");
token = token->next();
}
}
}
gotos.clear();
tok = beginfunction;
indentlevel = 0;
continue;
}
}
}
//---------------------------------------------------------------------------
// Helper functions for handling the tokens list
//---------------------------------------------------------------------------

View File

@ -206,6 +206,9 @@ private:
*/
bool simplifyKnownVariables();
/** Replace a "goto" with the statements */
void simplifyGoto();
/** Simplify "if else" */
bool elseif();

View File

@ -3000,7 +3000,7 @@ private:
" free(abc->a);\n"
" free(abc);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
TODO_ASSERT_EQUALS("", errout.str());
}
void ret()

View File

@ -554,15 +554,6 @@ private:
"}\n");
ASSERT_EQUALS("", errout.str());
checkNullPointer("void foo(struct ABC *abc)\n"
"{\n"
" int *a = abc->a;\n"
"out:\n"
" if (!abc)\n"
" ;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
// loops..
checkNullPointer("void freeAbc(struct ABC *abc)\n"
"{\n"

View File

@ -100,6 +100,9 @@ private:
// Simplify calculations
TEST_CASE(calculations);
// Simplify goto..
TEST_CASE(goto1);
}
std::string tok(const char code[])
@ -1203,6 +1206,62 @@ private:
}
}
void goto1()
{
{
const char code[] = "void foo()\n"
"{\n"
" if (a())\n"
" {\n"
" goto out;\n"
" }\n"
" b();\n"
"out:\n"
" c();\n"
"}";
const char expect[] = "void foo ( ) "
"{ "
"if ( a ( ) ) "
"{ "
"c ( ) ; "
"return ; "
"} "
"b ( ) ; "
"c ( ) ; "
"}";
ASSERT_EQUALS(expect, tok(code));
}
{
const char code[] = "void foo()\n"
"{\n"
" if (a())\n"
" goto out;\n"
" b();\n"
"out:\n"
" if (c())\n"
" d();\n"
"}";
const char expect[] = "void foo ( ) "
"{ "
"if ( a ( ) ) "
"{ "
"if ( c ( ) ) "
"d ( ) ; "
"return ; "
"} "
"b ( ) ; "
"if ( c ( ) ) "
"d ( ) ; "
"}";
ASSERT_EQUALS(expect, tok(code));
}
}
};
REGISTER_TEST(TestSimplifyTokens)