Tokenizer: Removed simplifyGoto as it's the cause of various FPs I see

This commit is contained in:
Daniel Marjamäki 2014-01-17 17:36:45 +01:00
parent 4eb746d7cc
commit 0203a4a6f5
4 changed files with 2 additions and 662 deletions

View File

@ -3530,8 +3530,6 @@ bool Tokenizer::simplifyTokenList2()
simplifyStd();
simplifyGoto();
if (_settings->terminated())
return false;
@ -7205,203 +7203,6 @@ void Tokenizer::simplifyOffsetPointerDereference()
}
}
void Tokenizer::simplifyGoto()
{
std::list<Token *> gotos;
unsigned int indentlevel = 0;
unsigned int indentspecial = 0;
Token *beginfunction = 0;
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->str() == "(" || tok->str() == "[")
tok = tok->link();
else if (Token::Match(tok, "class|namespace|struct|union %type% :|{")) {
tok = tok->tokAt(2);
while (tok && !Token::Match(tok, "[;{=]"))
tok = tok->next();
if (tok && tok->str() == "{")
++indentspecial;
else if (!tok)
break;
else
continue;
}
else if (Token::Match(tok, "namespace|struct|union {")) {
tok = tok->next();
++indentspecial;
}
else if (tok->str() == "{") {
if ((!beginfunction && !indentlevel) ||
(tok->previous() && tok->previous()->str() == "="))
tok = tok->link();
else
++indentlevel;
}
else if (tok->str() == "}") {
if (indentlevel == 0) {
if (indentspecial)
--indentspecial;
} else {
--indentlevel;
if (indentlevel == 0) {
gotos.clear();
beginfunction = 0;
}
}
}
if (!indentlevel && Token::Match(tok, ") const| {"))
beginfunction = tok;
else if (indentlevel && Token::Match(tok, "[{};] goto %var% ;"))
gotos.push_back(tok->next());
else if (indentlevel == 1 && Token::Match(tok, "[{};] %var% : ;") && tok->next()->str() != "default") {
// Is this label at the end..
bool end = false;
unsigned int level = 0;
for (const Token *tok2 = tok->tokAt(3); tok2; tok2 = tok2->next()) {
if (tok2->str() == "(" || tok2->str() == "[")
tok2 = tok2->link();
else if (tok2->str() == "{") {
++level;
}
else if (tok2->str() == "}") {
if (!level) {
end = true;
break;
}
--level;
}
if ((Token::Match(tok2, "[{};] %var% : ;") && tok2->next()->str() != "default") ||
Token::Match(tok2, "[{};] goto %var% ;")) {
break;
}
}
if (!end)
continue;
const std::string name(tok->next()->str());
tok->deleteNext(3);
// 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();
// change 'tok' before 'goto' if it coincides with the ';' token after 'name'
if (token->tokAt(3) == tok)
tok = token;
token->deleteNext(3);
// Insert the statements..
bool ret = false; // is there return
bool ret2 = false; // is there return in indentlevel 0
std::list<Token*> links;
std::list<Token*> links2;
std::list<Token*> links3;
unsigned int lev = 0;
unsigned int roundbraces = 0;
for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
if (tok2->str() == ")") {
if (!roundbraces)
break;
--roundbraces;
}
if (tok2->str() == "(")
++roundbraces;
if (!roundbraces && tok2->str() == "}") {
if (!lev)
break;
--lev;
} else if (!roundbraces && tok2->str() == "{") {
++lev;
} else if (!roundbraces && tok2->str() == "return") {
ret = true;
if (indentlevel == 1 && lev == 0)
ret2 = true;
}
token->insertToken(tok2->str());
token = token->next();
token->linenr(tok2->linenr());
token->varId(tok2->varId());
if (ret2 && roundbraces == 0 && tok2->str() == ";") {
break;
}
if (token->str() == "(") {
links.push_back(token);
} else if (token->str() == ")") {
if (links.empty()) {
// This should never happen at this point
syntaxError(token, ')');
return;
}
Token::createMutualLinks(links.back(), token);
links.pop_back();
} else if (token->str() == "{") {
links2.push_back(token);
} else if (token->str() == "}") {
if (links2.empty()) {
// This should never happen at this point
syntaxError(token, '}');
return;
}
Token::createMutualLinks(links2.back(), token);
links2.pop_back();
} else if (token->str() == "[") {
links3.push_back(token);
} else if (token->str() == "]") {
if (links3.empty()) {
// This should never happen at this point
syntaxError(token, ']');
return;
}
Token::createMutualLinks(links3.back(), token);
links3.pop_back();
}
}
if (!ret) {
token->insertToken(";");
token->insertToken("return");
}
}
}
// goto the end of the function
if (tok->str() == "{")
tok = tok->link();
else {
while (tok) {
if (tok->str() == "{")
tok = tok->link();
else if (tok->str() == "}")
break;
tok = tok->next();
}
}
if (!tok)
break;
gotos.clear();
beginfunction = 0;
indentlevel = 0;
continue;
}
}
}
void Tokenizer::simplifyNestedStrcat()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {

View File

@ -369,9 +369,6 @@ public:
*/
bool simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, unsigned int varid, const std::string &structname, std::string &value, unsigned int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel) const;
/** Replace a "goto" with the statements */
void simplifyGoto();
/** Simplify useless C++ empty namespaces, like: 'namespace %var% { }'*/
void simplifyEmptyNamespaces();

View File

@ -284,7 +284,6 @@ private:
Tokenizer tokenizer(&settings, &logger);
std::istringstream istr(code);
tokenizer.tokenize(istr, filename);
tokenizer.simplifyGoto();
// Check..
CheckOther checkOther(&tokenizer, &settings, &logger);
@ -2811,11 +2810,7 @@ private:
" return;\n"
" }\n"
"}");
// This fails because Tokenizer::simplifyGoto() copies the "leave:" block
// into where the goto is, but because it contains a "return", it omits
// copying a final return after the block.
TODO_ASSERT_EQUALS("",
"[test.cpp:5]: (style) Switch falls through case without comment. 'break;' missing?\n", errout.str());
ASSERT_EQUALS("", errout.str());
check_preprocess_suppress(
"void foo() {\n"

View File

@ -180,14 +180,6 @@ private:
TEST_CASE(calculations);
TEST_CASE(comparisons);
// Simplify goto..
TEST_CASE(goto1);
TEST_CASE(goto2);
TEST_CASE(goto3); // #3138
TEST_CASE(goto4); // #3459
TEST_CASE(goto5); // #3705 - return ({asm("");});
TEST_CASE(goto6);
//remove dead code after flow control statements
TEST_CASE(flowControl);
@ -520,20 +512,6 @@ private:
ASSERT_EQUALS("if ( ! p ) { ; }", tok("if (p == (char *)0);"));
ASSERT_EQUALS("return str ;", tok("return (char *)str;"));
{
const char code[] = "static void crash()\n"
"{\n"
" goto err_exit;\n"
"err_exit:\n"
" (void)foo();\n"
"}\n";
const char expected[] = "static void crash ( ) "
"{ foo ( ) ; return ; }";
ASSERT_EQUALS(expected, tok(code));
}
ASSERT_EQUALS("if ( * a )", tok("if ((char)*a)"));
ASSERT_EQUALS("if ( & a )", tok("if ((int)&a)"));
ASSERT_EQUALS("if ( * a )", tok("if ((unsigned int)(unsigned char)*a)"));
@ -3137,437 +3115,6 @@ private:
ASSERT_EQUALS("( 6 )", tok("( 1 > 2 && 3 > 4 ? 5 : 6 )"));
}
void goto1() {
{
const char code[] = "void foo()\n"
"{\n"
" if (a())\n"
" {\n"
" goto out;\n"
" }\n"
" b();\n"
"out:\n"
" c();\n"
"}";
errout.str("");
Settings settings;
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.simplifyTokenList2();
const char expect[] = "\n\n##file 0\n"
"1: void foo ( )\n"
"2: {\n"
"3: if ( a ( ) )\n"
"4: {\n"
"5:\n|\n8:\n"
"9: c ( ) ; return ; }\n"
"7: b ( ) ;\n"
"8:\n"
"9: c ( ) ;\n"
"10: }\n";
ASSERT_EQUALS(expect, tokenizer.tokens()->stringifyList());
}
{
const char code[] = "void foo()\n"
"{\n"
" if (a())\n"
" goto out;\n"
" b();\n"
"out:\n"
" if (c())\n"
" d();\n"
"}";
errout.str("");
Settings settings;
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.simplifyTokenList2();
const char expect[] = "\n\n##file 0\n"
"1: void foo ( )\n"
"2: {\n"
"3: if ( a ( ) ) {\n"
"4:\n5:\n6:\n"
"7: if ( c ( ) ) {\n"
"8: d ( ) ; } return ; }\n"
"5: b ( ) ;\n"
"6:\n"
"7: if ( c ( ) ) {\n"
"8: d ( ) ; }\n"
"9: }\n";
ASSERT_EQUALS(expect, tokenizer.tokens()->stringifyList());
}
{
const char code[] = "void foo()\n"
"{\n"
" if (a())\n"
" goto out;\n"
" b();\n"
"out:\n"
" if (c())\n"
" {\n"
" d();\n"
" }\n"
"}";
const char expect[] = "void foo ( ) "
"{ "
"if ( a ( ) ) "
"{ "
"if ( c ( ) ) "
"{ d ( ) ; } "
"return ; "
"} "
"b ( ) ; "
"if ( c ( ) ) "
"{ d ( ) ; } "
"}";
ASSERT_EQUALS(expect, tok(code));
}
{
const char code[] = "void foo(int x)\n"
"{\n"
" if (a())\n"
" goto out;\n"
" b();\n"
"out:\n"
" if (x)\n"
" {\n"
" x++; b[0]=x;\n"
" }\n"
"}";
const char expect[] = "void foo ( int x ) "
"{ "
"if ( a ( ) ) "
"{ "
"if ( x ) "
"{ x ++ ; b [ 0 ] = x ; } "
"return ; "
"} "
"b ( ) ; "
"if ( x ) "
"{ x ++ ; b [ 0 ] = x ; } "
"}";
ASSERT_EQUALS(expect, tok(code));
}
{
const char code[] = "class NoLabels { bool varOne : 1 ; bool varTwo : 1 ; } ;";
const char expect[] = "class NoLabels { bool varOne ; bool varTwo ; } ;";
ASSERT_EQUALS(expect, tok(code));
}
{
const char code[] = "void foo ( ) { int var ; var = x < y ? y : z ; } ;";
ASSERT_EQUALS(code, tok(code));
}
}
void goto2() {
// Don't simplify goto inside function call (macro)
const char code[] = "void f ( ) { slist_iter ( if ( a ) { goto dont_write ; } dont_write : ; x ( ) ; ) ; }";
ASSERT_EQUALS(code, tok(code));
//ticket #3229 (segmentation fault)
ASSERT_EQUALS("void f ( ) { MACRO ( return ; ) return ; }",tok("void f ( ) {goto label; label: MACRO(return;)}"));
}
void goto3() {
// Simplify goto inside the namespace|struct|class|union block
{
const char code[] = "namespace A1"
"{"
" void foo()"
" {"
" goto source ;"
" bleeh;"
" source:"
" boo();"
" }"
"}";
const char expected[] = "namespace A1 "
"{"
" void foo ( )"
" {"
" boo ( ) ; return ;"
" } "
"}";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "class A"
"{"
" int n,m;"
" A()"
" {"
" goto source ;"
" bleeh;"
" source:"
" boo();"
" }"
" void boo();"
"}";
const char expected[] = "class A "
"{"
" int n ; int m ;"
" A ( )"
" {"
" boo ( ) ; return ;"
" }"
" void boo ( ) ; "
"}";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "struct A"
"{"
" int n,m;"
" A() : m(0)"
" {"
" goto source;"
" bleeh;"
" source:"
" n=10;"
" }"
"}";
const char expected[] = "struct A "
"{"
" int n ; int m ;"
" A ( ) : m ( 0 )"
" {"
" n = 10 ; return ;"
" } "
"}";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "namespace A1"
"{"
" class A"
" {"
" int n,m;"
" A()"
" {"
" goto source ;"
" bleeh;"
" source:"
" boo();"
" }"
" void boo();"
" }"
"}";
const char expected[] = "namespace A1 "
"{"
" class A"
" {"
" int n ; int m ;"
" A ( )"
" {"
" boo ( ) ; return ;"
" }"
" void boo ( ) ;"
" } "
"}";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "namespace A1"
"{"
" namespace AA1"
" {"
" void foo1()"
" {"
" goto source1 ;"
" bleeh;"
" source1:"
" boo1();"
" }"
" }"
" namespace AA2"
" {"
" void foo2()"
" {"
" goto source2 ;"
" bleeh;"
" source2:"
" boo2();"
" }"
" }"
"}";
const char expected[] = "namespace A1 "
"{"
" namespace AA1"
" {"
" void foo1 ( )"
" {"
" boo1 ( ) ; return ;"
" }"
" }"
" namespace AA2"
" {"
" void foo2 ( )"
" {"
" boo2 ( ) ; return ;"
" }"
" } "
"}";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "union A1"
"{"
" int a; "
" double b; "
" A1() : b(3.22)"
" {"
" goto source ;"
" bleeh;"
" source:"
" a = 322;"
" }"
"}";
const char expected[] = "union A1 "
"{"
" int a ;"
" double b ;"
" A1 ( ) : b ( 3.22 )"
" {"
" a = 322 ; return ;"
" } "
"}";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "class A"
"{"
" int a; "
" double b; "
" A() : b(3.22)"
" {"
" goto source ;"
" bleeh;"
" source:"
" a = 322;"
" }"
"}"
"class A1 : public A"
"{"
" int a1; "
" double b1; "
" A1() : b1(3.22)"
" {"
" goto source1 ;"
" bleeh1;"
" source1:"
" a = 322;"
" }"
"}";
const char expected[] = "class A "
"{"
" int a ;"
" double b ;"
" A ( ) : b ( 3.22 )"
" {"
" a = 322 ;"
" return ;"
" } "
"} "
"class A1 : public A "
"{"
" int a1 ;"
" double b1 ;"
" A1 ( ) : b1 ( 3.22 )"
" {"
" a = 322 ;"
" return ;"
" } "
"}";
ASSERT_EQUALS(expected, tok(code));
}
}
void goto4() {
const char code[] = "int main()\n"
"{\n"
" goto SkipIncr;\n"
" do {\n"
" f();\n"
" SkipIncr:\n"
" printf(\".\");\n"
" } while (bar());\n"
"}\n";
const char expected[] = "int main ( ) "
"{"
" goto SkipIncr ;"
" do {"
" f ( ) ;"
" SkipIncr : ;"
" printf ( \".\" ) ;"
" } while ( bar ( ) ) ; "
"}";
ASSERT_EQUALS(expected, tok(code));
}
void goto5() {
const char code[] = "int foo() {\n"
" goto err;\n"
"err:\n"
" return ( { __asm__(X); } ); "
"}\n";
ASSERT_EQUALS("int foo ( ) {"
" return { asm ( \"X\" ) ; } ;"
" return { asm ( \"X\" ) ; } ; "
"}", tok(code));
}
void goto6() { // from code in linux that wasn't handled well
const char code1[] = "static void a() {\n"
"unlock:\n"
"}\n"
"\n"
"static void b() {\n"
" if (c)\n"
" goto defer;\n"
"defer:\n"
"}\n";
ASSERT_EQUALS("static void a ( ) { } "
"static void b ( ) { if ( c ) { return ; } }", tok(code1));
const char code2[] = "void a()\n"
"{\n"
" if (x) {}\n"
"unlock:\n"
"}\n"
"\n"
"void b()\n"
"{\n"
" { goto defer; }\n"
"defer:\n"
"}";
ASSERT_EQUALS("void a ( ) { if ( x ) { } } void b ( ) { return ; }", tok(code2));
}
void flowControl() {
std::list<std::string> beforedead;
//beforedead.push_back("return");
@ -8334,7 +7881,7 @@ private:
" }\n"
" } while ((t = type[c]) == LET && catenate());\n"
"}\n";
ASSERT_EQUALS("int evallex ( ) { int c ; int t ; do { c = macroid ( c ) ; if ( c == EOF_CHAR || c == '\n' ) { } t = type [ c ] ; } while ( t == LET && catenate ( ) ) ; }",
ASSERT_EQUALS("int evallex ( ) { int c ; int t ; again : ; do { c = macroid ( c ) ; if ( c == EOF_CHAR || c == '\n' ) { } t = type [ c ] ; } while ( t == LET && catenate ( ) ) ; }",
tok(code, true));
}