Fixed #498 (Tokenizer: simplify 'goto')
This commit is contained in:
parent
0c479b8c9f
commit
c25e1963b1
115
src/tokenize.cpp
115
src/tokenize.cpp
|
@ -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
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
@ -206,6 +206,9 @@ private:
|
|||
*/
|
||||
bool simplifyKnownVariables();
|
||||
|
||||
/** Replace a "goto" with the statements */
|
||||
void simplifyGoto();
|
||||
|
||||
/** Simplify "if else" */
|
||||
bool elseif();
|
||||
|
||||
|
|
|
@ -3000,7 +3000,7 @@ private:
|
|||
" free(abc->a);\n"
|
||||
" free(abc);\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
TODO_ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void ret()
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue