try to clarify error message

This commit is contained in:
Daniel Marjamäki 2017-12-11 22:10:00 +01:00
parent f31311b249
commit 3f36d4b5f4
3 changed files with 21 additions and 14 deletions

View File

@ -336,7 +336,7 @@ void CheckString::incorrectStringBooleanError(const Token *tok, const std::strin
// always true: strcmp(str,"a")==0 || strcmp(str,"b") // always true: strcmp(str,"a")==0 || strcmp(str,"b")
// TODO: Library configuration for string comparison functions // TODO: Library configuration for string comparison functions
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
void CheckString::overlappingStringComparisons() void CheckString::deadStrcmp()
{ {
if (!_settings->isEnabled(Settings::WARNING)) if (!_settings->isEnabled(Settings::WARNING))
return; return;
@ -399,14 +399,14 @@ void CheckString::overlappingStringComparisons()
args2[1]->isLiteral() && args2[1]->isLiteral() &&
args1[1]->str() != args2[1]->str() && args1[1]->str() != args2[1]->str() &&
isSameExpression(_tokenizer->isCPP(), true, args1[0], args2[0], _settings->library, true)) isSameExpression(_tokenizer->isCPP(), true, args1[0], args2[0], _settings->library, true))
overlappingStringComparisonsError(tok1, tok2); deadStrcmpError(tok1, tok2);
} }
} }
} }
} }
} }
void CheckString::overlappingStringComparisonsError(const Token *eq0, const Token *ne0) void CheckString::deadStrcmpError(const Token *eq0, const Token *ne0)
{ {
std::string eq0Expr(eq0 ? eq0->expressionString() : std::string("strcmp(x,\"abc\")")); std::string eq0Expr(eq0 ? eq0->expressionString() : std::string("strcmp(x,\"abc\")"));
if (eq0 && eq0->astParent()->str() == "!") if (eq0 && eq0->astParent()->str() == "!")
@ -414,7 +414,14 @@ void CheckString::overlappingStringComparisonsError(const Token *eq0, const Toke
else else
eq0Expr += " == 0"; eq0Expr += " == 0";
const std::string ne0Expr = (ne0 ? ne0->expressionString() : std::string("strcmp(x,\"def\")")) + " != 0"; const std::string ne0Expr = (ne0 ? ne0->expressionString() : std::string("strcmp(x,\"def\")")) + " != 0";
reportError(ne0, Severity::warning, "overlappingStringComparisons", "The comparison operator in '" + ne0Expr + "' should maybe be '==' instead, currently the expression '" + eq0Expr + "' is redundant.");
const Token *ortok = eq0;
while (ortok && ortok->str() != "||")
ortok = ortok->astParent();
const std::string expression = ortok ? ortok->expressionString() : (eq0Expr + " || " + ne0Expr);
reportError(ne0, Severity::warning, "deadStrcmp", "The expression '" + expression + "' has a dead string comparison. The expression is logically the same as \'" + ne0Expr + "\'.");
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -57,7 +57,7 @@ public:
checkString.strPlusChar(); checkString.strPlusChar();
checkString.checkSuspiciousStringCompare(); checkString.checkSuspiciousStringCompare();
checkString.stringLiteralWrite(); checkString.stringLiteralWrite();
checkString.overlappingStringComparisons(); checkString.deadStrcmp();
} }
/** @brief Run checks against the simplified token list */ /** @brief Run checks against the simplified token list */
@ -85,8 +85,8 @@ public:
/** @brief %Check for suspicious code that compares string literals for equality */ /** @brief %Check for suspicious code that compares string literals for equality */
void checkAlwaysTrueOrFalseStringCompare(); void checkAlwaysTrueOrFalseStringCompare();
/** @brief %Check for overlapping string comparisons */ /** @brief %Check for dead string comparison */
void overlappingStringComparisons(); void deadStrcmp();
/** @brief %Check for overlapping source and destination passed to sprintf() */ /** @brief %Check for overlapping source and destination passed to sprintf() */
void sprintfOverlappingData(); void sprintfOverlappingData();
@ -101,7 +101,7 @@ private:
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 suspiciousStringCompareError(const Token* tok, const std::string& var); void suspiciousStringCompareError(const Token* tok, const std::string& var);
void suspiciousStringCompareError_char(const Token* tok, const std::string& var); void suspiciousStringCompareError_char(const Token* tok, const std::string& var);
void overlappingStringComparisonsError(const Token* tok1, const Token *tok2); void deadStrcmpError(const Token* tok1, const Token *tok2);
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const { void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
CheckString c(nullptr, settings, errorLogger); CheckString c(nullptr, settings, errorLogger);
@ -115,7 +115,7 @@ private:
c.incorrectStringBooleanError(nullptr, "\"Hello World\""); c.incorrectStringBooleanError(nullptr, "\"Hello World\"");
c.alwaysTrueFalseStringCompareError(nullptr, "str1", "str2"); c.alwaysTrueFalseStringCompareError(nullptr, "str1", "str2");
c.alwaysTrueStringVariableCompareError(nullptr, "varname1", "varname2"); c.alwaysTrueStringVariableCompareError(nullptr, "varname1", "varname2");
c.overlappingStringComparisonsError(nullptr, nullptr); c.deadStrcmpError(nullptr, nullptr);
} }
static std::string myName() { static std::string myName() {
@ -130,7 +130,7 @@ private:
"- suspicious condition (string literals as boolean)\n" "- suspicious condition (string literals as boolean)\n"
"- suspicious comparison of a string literal with a char* variable\n" "- suspicious comparison of a string literal with a char* variable\n"
"- suspicious comparison of '\\0' with a char* variable\n" "- suspicious comparison of '\\0' with a char* variable\n"
"- overlapping string comparisons (strcmp(str,\"x\")==0 || strcmp(str,\"y\")!=0)\n"; "- dead string comparison; (strcmp(str,\"x\")==0 || strcmp(str,\"y\")) is logically the same as (strcmp(str,\"y\") != 0)\n";
} }
}; };
/// @} /// @}

View File

@ -52,7 +52,7 @@ private:
TEST_CASE(incorrectStringCompare); TEST_CASE(incorrectStringCompare);
TEST_CASE(overlappingStringComparisons); TEST_CASE(deadStrcmp);
} }
void check(const char code[], const char filename[] = "test.cpp") { void check(const char code[], const char filename[] = "test.cpp") {
@ -581,11 +581,11 @@ private:
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
} }
void overlappingStringComparisons() { void deadStrcmp() {
check("void f(const char *str) {\n" check("void f(const char *str) {\n"
" if (strcmp(str, \"abc\") == 0 || strcmp(str, \"def\")) {}\n" " if (strcmp(str, \"abc\") == 0 || strcmp(str, \"def\")) {}\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:2]: (warning) The comparison operator in 'strcmp(str,\"def\") != 0' should maybe be '==' instead, currently the expression 'strcmp(str,\"abc\") == 0' is redundant.\n", errout.str()); ASSERT_EQUALS("[test.cpp:2]: (warning) The expression 'strcmp(str,\"abc\")==0||strcmp(str,\"def\")' has a dead string comparison. The expression is logically the same as 'strcmp(str,\"def\") != 0'.\n", errout.str());
check("struct X {\n" check("struct X {\n"
" char *str;\n" " char *str;\n"
@ -594,7 +594,7 @@ private:
"void f(const struct X *x) {\n" "void f(const struct X *x) {\n"
" if (strcmp(x->str, \"abc\") == 0 || strcmp(x->str, \"def\")) {}\n" " if (strcmp(x->str, \"abc\") == 0 || strcmp(x->str, \"def\")) {}\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:6]: (warning) The comparison operator in 'strcmp(x->str,\"def\") != 0' should maybe be '==' instead, currently the expression 'strcmp(x->str,\"abc\") == 0' is redundant.\n", errout.str()); ASSERT_EQUALS("[test.cpp:6]: (warning) The expression 'strcmp(x->str,\"abc\")==0||strcmp(x->str,\"def\")' has a dead string comparison. The expression is logically the same as 'strcmp(x->str,\"def\") != 0'.\n", errout.str());
} }
}; };