From 8e90ad106cde4c8ded4db61d63a5d33112958543 Mon Sep 17 00:00:00 2001 From: Edoardo Prezioso Date: Wed, 5 Oct 2011 18:51:51 +0200 Subject: [PATCH] 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. --- lib/tokenize.cpp | 80 +++++++++++++++++++++-------- test/testtokenize.cpp | 115 +++++++++++++++++++++++------------------- 2 files changed, 124 insertions(+), 71 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 0a41fd026..6e7a81d96 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -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(); diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index ce9817a34..241cf1f53 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -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()