Fixed #3383: If there is an empty line between subsequent break statements, only issue a message for inconclusive checking

This commit is contained in:
PKEuS 2012-04-05 10:38:29 +02:00
parent 425cbea6b1
commit b0f571b25c
3 changed files with 47 additions and 18 deletions

View File

@ -1752,14 +1752,18 @@ void CheckOther::checkUnreachableCode()
labelName = tok->tokAt(1); labelName = tok->tokAt(1);
} }
if (secondBreak) { // Statements follow directly, no line between them. (#3383)
// TODO: Try to find a better way to avoid false positives due to preprocessor configurations.
bool inconclusive = secondBreak && (secondBreak->linenr()-1 > secondBreak->previous()->linenr());
if (secondBreak && (_settings->inconclusive || !inconclusive)) {
if (Token::Match(secondBreak, "continue|goto|throw") || if (Token::Match(secondBreak, "continue|goto|throw") ||
(secondBreak->str() == "return" && (tok->str() == "return" || secondBreak->strAt(1) == ";"))) { // return with value after statements like throw can be necessary to make a function compile (secondBreak->str() == "return" && (tok->str() == "return" || secondBreak->strAt(1) == ";"))) { // return with value after statements like throw can be necessary to make a function compile
duplicateBreakError(secondBreak); duplicateBreakError(secondBreak, inconclusive);
tok = Token::findmatch(secondBreak, "[}:]"); tok = Token::findmatch(secondBreak, "[}:]");
} else if (secondBreak->str() == "break") { // break inside switch as second break statement should not issue a warning } else if (secondBreak->str() == "break") { // break inside switch as second break statement should not issue a warning
if (tok->str() == "break") // If the previous was a break, too: Issue warning if (tok->str() == "break") // If the previous was a break, too: Issue warning
duplicateBreakError(secondBreak); duplicateBreakError(secondBreak, inconclusive);
else { else {
unsigned int indent = 0; unsigned int indent = 0;
for (const Token* tok2 = tok; tok2; tok2 = tok2->previous()) { // Check, if the enclosing scope is a switch (TODO: Can we use SymbolDatabase here?) for (const Token* tok2 = tok; tok2; tok2 = tok2->previous()) { // Check, if the enclosing scope is a switch (TODO: Can we use SymbolDatabase here?)
@ -1767,7 +1771,7 @@ void CheckOther::checkUnreachableCode()
indent++; indent++;
else if (indent == 0 && tok2->str() == "{" && tok2->strAt(-1) == ")") { else if (indent == 0 && tok2->str() == "{" && tok2->strAt(-1) == ")") {
if (tok2->previous()->link()->strAt(-1) != "switch") { if (tok2->previous()->link()->strAt(-1) != "switch") {
duplicateBreakError(secondBreak); duplicateBreakError(secondBreak, inconclusive);
break; break;
} else } else
break; break;
@ -1792,7 +1796,7 @@ void CheckOther::checkUnreachableCode()
} }
} }
if (!labelInFollowingLoop) if (!labelInFollowingLoop)
unreachableCodeError(secondBreak); unreachableCodeError(secondBreak, inconclusive);
tok = Token::findmatch(secondBreak, "[}:]"); tok = Token::findmatch(secondBreak, "[}:]");
} else } else
tok = secondBreak; tok = secondBreak;
@ -1803,15 +1807,24 @@ void CheckOther::checkUnreachableCode()
} }
} }
void CheckOther::duplicateBreakError(const Token *tok) void CheckOther::duplicateBreakError(const Token *tok, bool inconclusive)
{ {
if (inconclusive)
reportInconclusiveError(tok, Severity::style, "duplicateBreak",
"Consecutive return, break, continue, goto or throw statements are unnecessary.\n"
"The second of the two statements can never be executed, and so should be removed.");
else
reportError(tok, Severity::style, "duplicateBreak", reportError(tok, Severity::style, "duplicateBreak",
"Consecutive return, break, continue, goto or throw statements are unnecessary.\n" "Consecutive return, break, continue, goto or throw statements are unnecessary.\n"
"The second of the two statements can never be executed, and so should be removed."); "The second of the two statements can never be executed, and so should be removed.");
} }
void CheckOther::unreachableCodeError(const Token *tok) void CheckOther::unreachableCodeError(const Token *tok, bool inconclusive)
{ {
if (inconclusive)
reportInconclusiveError(tok, Severity::style, "unreachableCode",
"Statements following return, break, continue, goto or throw will never be executed.");
else
reportError(tok, Severity::style, "unreachableCode", reportError(tok, Severity::style, "unreachableCode",
"Statements following return, break, continue, goto or throw will never be executed."); "Statements following return, break, continue, goto or throw will never be executed.");
} }

View File

@ -300,8 +300,8 @@ private:
void duplicateExpressionError(const Token *tok1, const Token *tok2, const std::string &op); void duplicateExpressionError(const Token *tok1, const Token *tok2, const std::string &op);
void alwaysTrueFalseStringCompareError(const Token *tok, const std::string& str1, const std::string& str2); void alwaysTrueFalseStringCompareError(const Token *tok, const std::string& str1, const std::string& str2);
void alwaysTrueStringVariableCompareError(const Token *tok, const std::string& str1, const std::string& str2); void alwaysTrueStringVariableCompareError(const Token *tok, const std::string& str1, const std::string& str2);
void duplicateBreakError(const Token *tok); void duplicateBreakError(const Token *tok, bool inconclusive);
void unreachableCodeError(const Token* tok); void unreachableCodeError(const Token* tok, bool inconclusive);
void assignBoolToPointerError(const Token *tok); void assignBoolToPointerError(const Token *tok);
void unsignedLessThanZeroError(const Token *tok, const std::string &varname, bool inconclusive); void unsignedLessThanZeroError(const Token *tok, const std::string &varname, bool inconclusive);
void unsignedPositiveError(const Token *tok, const std::string &varname, bool inconclusive); void unsignedPositiveError(const Token *tok, const std::string &varname, bool inconclusive);
@ -359,8 +359,8 @@ private:
c.duplicateExpressionError(0, 0, "&&"); c.duplicateExpressionError(0, 0, "&&");
c.alwaysTrueFalseStringCompareError(0, "str1", "str2"); c.alwaysTrueFalseStringCompareError(0, "str1", "str2");
c.alwaysTrueStringVariableCompareError(0, "varname1", "varname2"); c.alwaysTrueStringVariableCompareError(0, "varname1", "varname2");
c.duplicateBreakError(0); c.duplicateBreakError(0, false);
c.unreachableCodeError(0); c.unreachableCodeError(0, false);
c.unsignedLessThanZeroError(0, "varname", false); c.unsignedLessThanZeroError(0, "varname", false);
c.unsignedPositiveError(0, "varname", false); c.unsignedPositiveError(0, "varname", false);
c.bitwiseOnBooleanError(0, "varname", "&&"); c.bitwiseOnBooleanError(0, "varname", "&&");

View File

@ -159,13 +159,13 @@ private:
TEST_CASE(checkDoubleFree); TEST_CASE(checkDoubleFree);
} }
void check(const char code[], const char *filename = NULL, bool experimental = false) { void check(const char code[], const char *filename = NULL, bool experimental = false, bool inconclusive = true) {
// Clear the error buffer.. // Clear the error buffer..
errout.str(""); errout.str("");
Settings settings; Settings settings;
settings.addEnabled("style"); settings.addEnabled("style");
settings.inconclusive = true; settings.inconclusive = inconclusive;
settings.experimental = experimental; settings.experimental = experimental;
// Tokenize.. // Tokenize..
@ -2043,6 +2043,22 @@ private:
ASSERT_EQUALS("", errout.str()); // #3457 ASSERT_EQUALS("", errout.str()); // #3457
check("%: return ; ()"); // Don't crash. #3441. check("%: return ; ()"); // Don't crash. #3441.
// #3383. TODO: Use preprocessor
check("int foo() {\n"
"\n" // #ifdef A
" return 0;\n"
"\n" // #endif
" return 1;\n"
"}", 0, false, false);
ASSERT_EQUALS("", errout.str());
check("int foo() {\n"
"\n" // #ifdef A
" return 0;\n"
"\n" // #endif
" return 1;\n"
"}");
ASSERT_EQUALS("[test.cpp:5]: (style) Consecutive return, break, continue, goto or throw statements are unnecessary.\n", errout.str());
} }