Fixed ticket #3148 (Analysis failed on "Modules/mathmodule.c")

Fix: Do not handle code when 'return' is inside a macro. This is valid also for 'switch' code inside a macro.
This commit is contained in:
Edoardo Prezioso 2011-10-05 18:51:51 +02:00
parent 7436dd02ba
commit 8e90ad106c
2 changed files with 124 additions and 71 deletions

View File

@ -4908,11 +4908,21 @@ void Tokenizer::removeRedundantCodeAfterReturn()
{
unsigned int indentlevel = 0;
unsigned int indentcase = 0;
unsigned int indentret = 0; //this is the indentation level when 'return ;' token is found;
unsigned int indentret = 0;
unsigned int indentswitch = 0;
unsigned int indentlabel = 0;
unsigned int roundbraces = 0;
for (Token *tok = _tokens; tok; tok = tok->next())
{
if (tok->str() == "(")
++roundbraces;
else if (tok->str() == ")")
{
if (!roundbraces)
break; //too many ending round parenthesis
--roundbraces;
}
if (tok->str() == "{")
{
++indentlevel;
@ -4929,8 +4939,7 @@ void Tokenizer::removeRedundantCodeAfterReturn()
break;
--indentlevel1;
}
else if (Token::Match(tok2, "%var% : ;")
&& tok2->str()!="case" && tok2->str()!="default")
else if (Token::Match(tok2, "%var% : ;") && !Token::Match(tok2, "case!default"))
{
indentlabel = indentlevel1;
break;
@ -4943,12 +4952,10 @@ void Tokenizer::removeRedundantCodeAfterReturn()
}
}
}
else if (tok->str() == "}")
{
if (indentlevel == 0)
break; // break out - it seems the code is wrong
//there's already a 'return ;' and more indentation!
if (!indentlevel)
break; //too many closing parenthesis
if (indentret)
{
if (!indentswitch || indentlevel > indentcase)
@ -4990,26 +4997,44 @@ void Tokenizer::removeRedundantCodeAfterReturn()
{
if (tok->str() == "switch")
{
if (indentlevel == 0)
if (!indentlevel)
break;
// Don't care about unpreprocessed macros part of code
if (roundbraces)
break;
unsigned int switchroundbraces = 0;
for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next())
{
if (tok2->str() == "(")
++switchroundbraces;
else if (tok2->str() == ")")
{
if (!switchroundbraces)
break; //too many closing parenthesis
--switchroundbraces;
}
if (tok2->str() == "{")
{
if (switchroundbraces)
{
tok = tok2->previous();
break; //too many opening parenthesis
}
tok = tok2;
++indentswitch;
break;
}
else if (tok2->str() == "}")
break; //bad code
break; //it's not expected, hence it's bad code
}
if (!indentswitch)
break;
++indentlevel;
indentcase = indentlevel;
}
else if (indentswitch
&& (tok->str() == "case" || tok->str() == "default"))
else if (indentswitch && Token::Match(tok, "case|default"))
{
if (indentlevel > indentcase)
{
@ -5017,7 +5042,7 @@ void Tokenizer::removeRedundantCodeAfterReturn()
}
for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next())
{
if (tok2->str() == ":" || Token::Match(tok2, ": ;"))
if (Token::Match(tok2, ": ;| "))
{
if (indentlevel == indentcase)
{
@ -5026,25 +5051,40 @@ void Tokenizer::removeRedundantCodeAfterReturn()
tok = tok2;
break;
}
else if (tok2->str() == "}" || tok2->str() == "{")
else if (Token::Match(tok2, "[{}]"))
break; //bad code
}
}
else if (tok->str() == "return")
else if (tok->str()=="return")
{
if (indentlevel == 0)
break; // break out - never seen a 'return' not inside a scope;
if (!indentlevel)
break;
// Don't care about unpreprocessed macros part of code
if (roundbraces)
continue;
//catch the first ';' after the return
unsigned int returnroundbraces = 0;
for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next())
{
if (tok2->str() == ";")
if (tok2->str() == "(")
++returnroundbraces;
else if (tok2->str() == ")")
{
if (!returnroundbraces)
break; //excessive closing parenthesis
--returnroundbraces;
}
else if (tok2->str() == ";")
{
if (returnroundbraces)
break; //excessive opening parenthesis
indentret = indentlevel;
tok = tok2;
break;
}
else if (tok2->str() == "{" || tok2->str() == "}")
else if (Token::Match(tok2, "[{}]"))
break; //I think this is an error code...
}
if (!indentret)
@ -5055,7 +5095,7 @@ void Tokenizer::removeRedundantCodeAfterReturn()
{
if (!indentswitch || indentlevel > indentcase+1)
{
if (indentlevel >= indentret && (!(Token::Match(tok, "%var% : ;")) || tok->str()=="case" || tok->str()=="default"))
if (indentlevel >= indentret && (!Token::Match(tok, "%var% : ;") || Token::Match(tok, "case|default")))
{
tok = tok->previous();
tok->deleteNext();
@ -5067,7 +5107,7 @@ void Tokenizer::removeRedundantCodeAfterReturn()
}
else
{
if (!(Token::Match(tok, "%var% : ;")) && tok -> str() != "case" && tok->str() != "default")
if (!Token::Match(tok, "%var% : ;") && !Token::Match(tok, "case|default"))
{
tok = tok->previous();
tok->deleteNext();

View File

@ -358,7 +358,11 @@ private:
TEST_CASE(simplifyIfAddBraces); // ticket # 2739 (segmentation fault)
//remove redundant code after the 'return ;' statement
TEST_CASE(removeRedundantCodeAfterReturn);
TEST_CASE(removeRedundantCodeAfterReturn1);
TEST_CASE(removeRedundantCodeAfterReturn2);
TEST_CASE(removeRedundantCodeAfterReturn3);
TEST_CASE(removeRedundantCodeAfterReturn4);
TEST_CASE(removeRedundantCodeAfterReturn5);
TEST_CASE(platformWin32);
TEST_CASE(platformWin32A);
@ -5922,7 +5926,7 @@ private:
}
}
void removeRedundantCodeAfterReturn()
void removeRedundantCodeAfterReturn1()
{
ASSERT_EQUALS("void f ( ) { return ; }", tokenizeAndStringify("void f() { return; foo();}"));
ASSERT_EQUALS("void f ( int n ) { if ( n ) { return ; } foo ( ) ; }",tokenizeAndStringify("void f(int n) { if (n) return; foo();}"));
@ -5931,58 +5935,67 @@ private:
tokenizeAndStringify("int f(int n) { switch (n) {case 0: return 0; n*=2; default: return n; n*=6;} return -1; foo();}"));
//ticket #3132
ASSERT_EQUALS("void f ( int i ) { goto label ; switch ( i ) { label : ; return ; } }",tokenizeAndStringify("void f (int i) { goto label; switch(i) { label: return; } }"));
//ticket #3148
ASSERT_EQUALS("void f ( ) { MACRO ( return 0 ) }",tokenizeAndStringify("void f() { MACRO(return NULL) }"));
ASSERT_EQUALS("void f ( ) { MACRO ( return ; , 0 ) }",tokenizeAndStringify("void f() { MACRO(return;, NULL) }"));
ASSERT_EQUALS("void f ( ) { MACRO ( bar1 , return 0 ) }",tokenizeAndStringify("void f() { MACRO(bar1, return NULL) }"));
ASSERT_EQUALS("void f ( ) { MACRO ( return ; bar2 , foo ) }",tokenizeAndStringify("void f() { MACRO(return; bar2, foo) }"));
}
{
const char code[] = "void f(){ "
"if (k>0) goto label; "
"return; "
"if (tnt) "
" { "
" { "
" check(); "
" k=0; "
" } "
" label: "
" bar(); "
" } "
"}";
ASSERT_EQUALS("void f ( ) { if ( 0 < k ) { goto label ; } return ; { label : ; bar ( ) ; } }",simplifyKnownVariables(code));
}
void removeRedundantCodeAfterReturn2()
{
const char code[] = "void f(){ "
"if (k>0) goto label; "
"return; "
"if (tnt) "
" { "
" { "
" check(); "
" k=0; "
" } "
" label: "
" bar(); "
" } "
"}";
ASSERT_EQUALS("void f ( ) { if ( 0 < k ) { goto label ; } return ; { label : ; bar ( ) ; } }",simplifyKnownVariables(code));
}
{
const char code[] = "int f() { "
"switch (x) { case 1: return 1; bar(); tack; { ticak(); return; } return; "
"case 2: return 2; { reere(); } tack(); "
"switch(y) { case 1: return 0; case 2: return 7; } "
"return 2; } return 3; }";
ASSERT_EQUALS("int f ( ) { switch ( x ) { case 1 : return 1 ; case 2 : return 2 ; } return 3 ; }",simplifyKnownVariables(code));
}
void removeRedundantCodeAfterReturn3()
{
const char code[] = "int f() { "
"switch (x) { case 1: return 1; bar(); tack; { ticak(); return; } return; "
"case 2: return 2; { random(); } tack(); "
"switch(y) { case 1: return 0; case 2: return 7; } "
"return 2; } return 3; }";
ASSERT_EQUALS("int f ( ) { switch ( x ) { case 1 : return 1 ; case 2 : return 2 ; } return 3 ; }",simplifyKnownVariables(code));
}
{
const char code[] = "int f() {"
"switch (x) { case 1: return 1; bar(); tack; { ticak(); return; } return;"
"case 2: switch(y) { case 1: return 0; bar2(); foo(); case 2: return 7; }"
"return 2; } return 3; }";
const char expected[] = "int f ( ) {"
" switch ( x ) { case 1 : return 1 ;"
" case 2 : switch ( y ) { case 1 : return 0 ; case 2 : return 7 ; }"
" return 2 ; } return 3 ; }";
ASSERT_EQUALS(expected,simplifyKnownVariables(code));
}
//ticket #3146
{
const char code[] = "void foo () {"
" switch (i) { case 0: switch (j) { case 0: return -1; }"
" case 1: switch (j) { case -1: return -1; }"
" case 2: switch (j) { case -2: return -1; }"
" case 3: if (blah6) return -1; break; } }";
const char expected[] = "void foo ( ) {"
" switch ( i ) { case 0 : switch ( j ) { case 0 : return -1 ; }"
" case 1 : switch ( j ) { case -1 : return -1 ; }"
" case 2 : switch ( j ) { case -2 : return -1 ; }"
" case 3 : if ( blah6 ) { return -1 ; } break ; } }";
ASSERT_EQUALS(expected, simplifyKnownVariables(code));
}
void removeRedundantCodeAfterReturn4()
{
const char code[] = "int f() {"
"switch (x) { case 1: return 1; bar(); tack; { ticak(); return; } return;"
"case 2: switch(y) { case 1: return 0; bar2(); foo(); case 2: return 7; }"
"return 2; } return 3; }";
const char expected[] = "int f ( ) {"
" switch ( x ) { case 1 : return 1 ;"
" case 2 : switch ( y ) { case 1 : return 0 ; case 2 : return 7 ; }"
" return 2 ; } return 3 ; }";
ASSERT_EQUALS(expected,simplifyKnownVariables(code));
}
void removeRedundantCodeAfterReturn5()
{
const char code[] = "void foo () {"
" switch (i) { case 0: switch (j) { case 0: return -1; }"
" case 1: switch (j) { case -1: return -1; }"
" case 2: switch (j) { case -2: return -1; }"
" case 3: if (blah6) return -1; break; } }";
const char expected[] = "void foo ( ) {"
" switch ( i ) { case 0 : switch ( j ) { case 0 : return -1 ; }"
" case 1 : switch ( j ) { case -1 : return -1 ; }"
" case 2 : switch ( j ) { case -2 : return -1 ; }"
" case 3 : if ( blah6 ) { return -1 ; } break ; } }";
ASSERT_EQUALS(expected, simplifyKnownVariables(code));
}
void platformWin32()