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

View File

@ -358,7 +358,11 @@ private:
TEST_CASE(simplifyIfAddBraces); // ticket # 2739 (segmentation fault) TEST_CASE(simplifyIfAddBraces); // ticket # 2739 (segmentation fault)
//remove redundant code after the 'return ;' statement //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(platformWin32);
TEST_CASE(platformWin32A); 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 ( ) { 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();}")); ASSERT_EQUALS("void f ( int n ) { if ( n ) { return ; } foo ( ) ; }",tokenizeAndStringify("void f(int n) { if (n) return; foo();}"));
@ -5931,7 +5935,14 @@ private:
tokenizeAndStringify("int f(int n) { switch (n) {case 0: return 0; n*=2; default: return n; n*=6;} return -1; foo();}")); tokenizeAndStringify("int f(int n) { switch (n) {case 0: return 0; n*=2; default: return n; n*=6;} return -1; foo();}"));
//ticket #3132 //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; } }")); 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) }"));
}
void removeRedundantCodeAfterReturn2()
{ {
const char code[] = "void f(){ " const char code[] = "void f(){ "
"if (k>0) goto label; " "if (k>0) goto label; "
@ -5949,15 +5960,17 @@ private:
ASSERT_EQUALS("void f ( ) { if ( 0 < k ) { goto label ; } return ; { label : ; bar ( ) ; } }",simplifyKnownVariables(code)); ASSERT_EQUALS("void f ( ) { if ( 0 < k ) { goto label ; } return ; { label : ; bar ( ) ; } }",simplifyKnownVariables(code));
} }
void removeRedundantCodeAfterReturn3()
{ {
const char code[] = "int f() { " const char code[] = "int f() { "
"switch (x) { case 1: return 1; bar(); tack; { ticak(); return; } return; " "switch (x) { case 1: return 1; bar(); tack; { ticak(); return; } return; "
"case 2: return 2; { reere(); } tack(); " "case 2: return 2; { random(); } tack(); "
"switch(y) { case 1: return 0; case 2: return 7; } " "switch(y) { case 1: return 0; case 2: return 7; } "
"return 2; } return 3; }"; "return 2; } return 3; }";
ASSERT_EQUALS("int f ( ) { switch ( x ) { case 1 : return 1 ; case 2 : return 2 ; } return 3 ; }",simplifyKnownVariables(code)); ASSERT_EQUALS("int f ( ) { switch ( x ) { case 1 : return 1 ; case 2 : return 2 ; } return 3 ; }",simplifyKnownVariables(code));
} }
void removeRedundantCodeAfterReturn4()
{ {
const char code[] = "int f() {" const char code[] = "int f() {"
"switch (x) { case 1: return 1; bar(); tack; { ticak(); return; } return;" "switch (x) { case 1: return 1; bar(); tack; { ticak(); return; } return;"
@ -5969,7 +5982,8 @@ private:
" return 2 ; } return 3 ; }"; " return 2 ; } return 3 ; }";
ASSERT_EQUALS(expected,simplifyKnownVariables(code)); ASSERT_EQUALS(expected,simplifyKnownVariables(code));
} }
//ticket #3146
void removeRedundantCodeAfterReturn5()
{ {
const char code[] = "void foo () {" const char code[] = "void foo () {"
" switch (i) { case 0: switch (j) { case 0: return -1; }" " switch (i) { case 0: switch (j) { case 0: return -1; }"
@ -5983,7 +5997,6 @@ private:
" case 3 : if ( blah6 ) { return -1 ; } break ; } }"; " case 3 : if ( blah6 ) { return -1 ; } break ; } }";
ASSERT_EQUALS(expected, simplifyKnownVariables(code)); ASSERT_EQUALS(expected, simplifyKnownVariables(code));
} }
}
void platformWin32() void platformWin32()
{ {