Fixed #2722 (new check: statement that is always true (strcmp))
This commit is contained in:
parent
c6f71321bd
commit
46645ab327
|
@ -3296,6 +3296,58 @@ void CheckOther::duplicateExpressionError(const Token *tok1, const Token *tok2,
|
||||||
"determine if it is correct.");
|
"determine if it is correct.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
// Check for string comparison involving two static strings.
|
||||||
|
// if(strcmp("00FF00","00FF00")==0) // <- statement is always true
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void CheckOther::checkAlwaysTrueOrFalseStringCompare()
|
||||||
|
{
|
||||||
|
if (!_settings->_checkCodingStyle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const char pattern1[] = "strcmp|stricmp|strcmpi|strcasecmp|wcscmp ( %str% , %str% )";
|
||||||
|
const char pattern2[] = "QString :: compare ( %str% , %str% )";
|
||||||
|
|
||||||
|
const Token *tok = _tokenizer->tokens();
|
||||||
|
while (tok && (tok = Token::findmatch(tok, pattern1)) != NULL)
|
||||||
|
{
|
||||||
|
alwaysTrueFalseStringCompare(tok, tok->strAt(2), tok->strAt(4));
|
||||||
|
tok = tok->tokAt(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
tok = _tokenizer->tokens();
|
||||||
|
while (tok && (tok = Token::findmatch(tok, pattern2)) != NULL)
|
||||||
|
{
|
||||||
|
alwaysTrueFalseStringCompare(tok, tok->strAt(4), tok->strAt(6));
|
||||||
|
tok = tok->tokAt(7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckOther::alwaysTrueFalseStringCompare(const Token *tok, const std::string& str1, const std::string& str2)
|
||||||
|
{
|
||||||
|
const size_t stringLen = 10;
|
||||||
|
const std::string string1 = (str1.size() < stringLen) ? str1 : (str1.substr(0, stringLen-2) + "..");
|
||||||
|
const std::string string2 = (str2.size() < stringLen) ? str2 : (str2.substr(0, stringLen-2) + "..");
|
||||||
|
|
||||||
|
if (str1 == str2)
|
||||||
|
{
|
||||||
|
reportError(tok, Severity::warning, "staticStringCompare",
|
||||||
|
"Comparison of always identical static strings.\n"
|
||||||
|
"The compared strings, '" + string1 + "' and '" + string2 + "', are always identical. "
|
||||||
|
"If the purpose is to compare these two strings, the comparison is unnecessary. "
|
||||||
|
"If the strings are supposed to be different, then there is a bug somewhere.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reportError(tok, Severity::performance, "staticStringCompare",
|
||||||
|
"Unnecessary comparison of static strings.\n"
|
||||||
|
"The compared strings, '" + string1 + "' and '" + string2 + "', are static and always different. "
|
||||||
|
"If the purpose is to compare these two strings, the comparison is unnecessary.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
void CheckOther::cstyleCastError(const Token *tok)
|
void CheckOther::cstyleCastError(const Token *tok)
|
||||||
|
|
|
@ -98,6 +98,7 @@ public:
|
||||||
checkOther.checkIncrementBoolean();
|
checkOther.checkIncrementBoolean();
|
||||||
checkOther.checkComparisonOfBoolWithInt();
|
checkOther.checkComparisonOfBoolWithInt();
|
||||||
checkOther.checkSwitchCaseFallThrough();
|
checkOther.checkSwitchCaseFallThrough();
|
||||||
|
checkOther.checkAlwaysTrueOrFalseStringCompare();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Clarify calculation for ".. a * b ? .." */
|
/** @brief Clarify calculation for ".. a * b ? .." */
|
||||||
|
@ -216,6 +217,9 @@ public:
|
||||||
/** @brief %Check for suspicious code with the same expression on both sides of operator (e.g "if (a && a)") */
|
/** @brief %Check for suspicious code with the same expression on both sides of operator (e.g "if (a && a)") */
|
||||||
void checkDuplicateExpression();
|
void checkDuplicateExpression();
|
||||||
|
|
||||||
|
/** @brief %Check for suspicious code that compares string literals for equality */
|
||||||
|
void checkAlwaysTrueOrFalseStringCompare();
|
||||||
|
|
||||||
// Error messages..
|
// Error messages..
|
||||||
void cstyleCastError(const Token *tok);
|
void cstyleCastError(const Token *tok);
|
||||||
void dangerousUsageStrtolError(const Token *tok);
|
void dangerousUsageStrtolError(const Token *tok);
|
||||||
|
@ -247,6 +251,7 @@ public:
|
||||||
void duplicateIfError(const Token *tok1, const Token *tok2);
|
void duplicateIfError(const Token *tok1, const Token *tok2);
|
||||||
void duplicateBranchError(const Token *tok1, const Token *tok2);
|
void duplicateBranchError(const Token *tok1, const Token *tok2);
|
||||||
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 alwaysTrueFalseStringCompare(const Token *tok, const std::string& str1, const std::string& str2);
|
||||||
|
|
||||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
|
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings)
|
||||||
{
|
{
|
||||||
|
@ -294,6 +299,7 @@ public:
|
||||||
c.duplicateIfError(0, 0);
|
c.duplicateIfError(0, 0);
|
||||||
c.duplicateBranchError(0, 0);
|
c.duplicateBranchError(0, 0);
|
||||||
c.duplicateExpressionError(0, 0, "&&");
|
c.duplicateExpressionError(0, 0, "&&");
|
||||||
|
c.alwaysTrueFalseStringCompare(0, "str1", "str2");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string myName() const
|
std::string myName() const
|
||||||
|
@ -336,7 +342,8 @@ public:
|
||||||
"* Clarify calculation with parentheses\n"
|
"* Clarify calculation with parentheses\n"
|
||||||
"* using increment on boolean\n"
|
"* using increment on boolean\n"
|
||||||
"* comparison of a boolean with a non-zero integer\n"
|
"* comparison of a boolean with a non-zero integer\n"
|
||||||
"* suspicious condition (assignment+comparison)"
|
"* suspicious condition (assignment+comparison)\n"
|
||||||
|
"* suspicious condition (runtime comparison of string literals)\n"
|
||||||
|
|
||||||
// optimisations
|
// optimisations
|
||||||
"* optimisation: detect post increment/decrement\n";
|
"* optimisation: detect post increment/decrement\n";
|
||||||
|
|
|
@ -117,6 +117,8 @@ private:
|
||||||
TEST_CASE(duplicateBranch);
|
TEST_CASE(duplicateBranch);
|
||||||
TEST_CASE(duplicateExpression1);
|
TEST_CASE(duplicateExpression1);
|
||||||
TEST_CASE(duplicateExpression2); // ticket #2730
|
TEST_CASE(duplicateExpression2); // ticket #2730
|
||||||
|
|
||||||
|
TEST_CASE(alwaysTrueFalseStringCompare);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char code[], const char *filename = NULL)
|
void check(const char code[], const char *filename = NULL)
|
||||||
|
@ -216,6 +218,7 @@ private:
|
||||||
// Check..
|
// Check..
|
||||||
CheckOther checkOther(&tokenizer, &settings, &logger);
|
CheckOther checkOther(&tokenizer, &settings, &logger);
|
||||||
checkOther.checkSwitchCaseFallThrough();
|
checkOther.checkSwitchCaseFallThrough();
|
||||||
|
checkOther.checkAlwaysTrueOrFalseStringCompare();
|
||||||
|
|
||||||
logger.reportUnmatchedSuppressions(settings.nomsg.getUnmatchedLocalSuppressions(filename));
|
logger.reportUnmatchedSuppressions(settings.nomsg.getUnmatchedLocalSuppressions(filename));
|
||||||
}
|
}
|
||||||
|
@ -2549,6 +2552,51 @@ private:
|
||||||
"[test.cpp:8]: (error) Passing value -1.0 to sqrt() leads to undefined result\n"
|
"[test.cpp:8]: (error) Passing value -1.0 to sqrt() leads to undefined result\n"
|
||||||
"[test.cpp:9]: (error) Passing value -1.0 to sqrtf() leads to undefined result\n", errout.str());
|
"[test.cpp:9]: (error) Passing value -1.0 to sqrtf() leads to undefined result\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void alwaysTrueFalseStringCompare()
|
||||||
|
{
|
||||||
|
check_preprocess_suppress(
|
||||||
|
"#define MACRO \"00FF00\"\n"
|
||||||
|
"int main()\n"
|
||||||
|
"{\n"
|
||||||
|
" if (strcmp(MACRO,\"00FF00\") == 0)"
|
||||||
|
" {"
|
||||||
|
" std::cout << \"Equal\n\""
|
||||||
|
" }"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (warning) Comparison of always identical static strings.\n", errout.str());
|
||||||
|
|
||||||
|
check_preprocess_suppress(
|
||||||
|
"int main()\n"
|
||||||
|
"{\n"
|
||||||
|
" if (stricmp(\"hotdog\",\"HOTdog\") == 0)"
|
||||||
|
" {"
|
||||||
|
" std::cout << \"Equal\n\""
|
||||||
|
" }"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3]: (performance) Unnecessary comparison of static strings.\n", errout.str());
|
||||||
|
|
||||||
|
check_preprocess_suppress(
|
||||||
|
"#define MACRO \"Hotdog\"\n"
|
||||||
|
"int main()\n"
|
||||||
|
"{\n"
|
||||||
|
" if (QString::compare(\"Hamburger\", MACRO) == 0)"
|
||||||
|
" {"
|
||||||
|
" std::cout << \"Equal\n\""
|
||||||
|
" }"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (performance) Unnecessary comparison of static strings.\n", errout.str());
|
||||||
|
|
||||||
|
check_preprocess_suppress(
|
||||||
|
"int main()\n"
|
||||||
|
"{\n"
|
||||||
|
" if (QString::compare(argv[2], \"hotdog\") == 0)"
|
||||||
|
" {"
|
||||||
|
" std::cout << \"Equal\n\""
|
||||||
|
" }"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestOther)
|
REGISTER_TEST(TestOther)
|
||||||
|
|
Loading…
Reference in New Issue