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,17 +1807,26 @@ void CheckOther::checkUnreachableCode()
} }
} }
void CheckOther::duplicateBreakError(const Token *tok) void CheckOther::duplicateBreakError(const Token *tok, bool inconclusive)
{ {
reportError(tok, Severity::style, "duplicateBreak", if (inconclusive)
"Consecutive return, break, continue, goto or throw statements are unnecessary.\n" reportInconclusiveError(tok, Severity::style, "duplicateBreak",
"The second of the two statements can never be executed, and so should be removed."); "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",
"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.");
} }
void CheckOther::unreachableCodeError(const Token *tok) void CheckOther::unreachableCodeError(const Token *tok, bool inconclusive)
{ {
reportError(tok, Severity::style, "unreachableCode", if (inconclusive)
"Statements following return, break, continue, goto or throw will never be executed."); reportInconclusiveError(tok, Severity::style, "unreachableCode",
"Statements following return, break, continue, goto or throw will never be executed.");
else
reportError(tok, Severity::style, "unreachableCode",
"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());
} }