Fixed #1530 (possible new check: strlen return value versus zero.)

This commit is contained in:
Zachary Blair 2010-04-13 19:30:25 +02:00 committed by Daniel Marjamäki
parent a7903c3385
commit bd7dc9946e
3 changed files with 88 additions and 1 deletions

View File

@ -215,8 +215,37 @@ void CheckOther::redundantCondition2()
} }
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// "if (strlen(s))" can be rewritten as "if (*s != '\0')"
//---------------------------------------------------------------------------
void CheckOther::checkEmptyStringTest()
{
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{
// Non-empty string tests
if (Token::Match(tok, "if ( strlen ( %any% ) )"))
{
emptyStringTestError(tok, tok->strAt(4), false);
}
else if (Token::Match(tok, "strlen ( %any% ) !=|> 0"))
{
emptyStringTestError(tok, tok->strAt(2), false);
}
else if (Token::Match(tok, "0 < strlen ( %any% )"))
{
emptyStringTestError(tok, tok->strAt(4), false);
}
// Empty string tests
else if (Token::Match(tok, "! strlen ( %any% )"))
{
emptyStringTestError(tok, tok->strAt(3), true);
}
else if (Token::Match(tok, "strlen ( %any% ) == 0"))
{
emptyStringTestError(tok, tok->strAt(2), true);
}
}
}
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// strtol(str, 0, radix) <- radix must be 0 or 2-36 // strtol(str, 0, radix) <- radix must be 0 or 2-36
@ -2760,3 +2789,17 @@ void CheckOther::postIncrementError(const Token *tok, const std::string &var_nam
std::string type = (isIncrement ? "Incrementing" : "Decrementing"); std::string type = (isIncrement ? "Incrementing" : "Decrementing");
reportError(tok, Severity::possibleStyle, "postIncrementDecrement", ("Pre-" + type + " variable '" + var_name + "' is preferred to Post-" + type)); reportError(tok, Severity::possibleStyle, "postIncrementDecrement", ("Pre-" + type + " variable '" + var_name + "' is preferred to Post-" + type));
} }
void CheckOther::emptyStringTestError(const Token *tok, const std::string &var_name, const bool isTestForEmpty)
{
if (isTestForEmpty)
{
reportError(tok, Severity::possibleStyle,
"emptyStringTest", "Empty string test can be simplified to \"*" + var_name + " == '\\0'\"");
}
else
{
reportError(tok, Severity::possibleStyle,
"emptyStringTest", "Non-empty string test can be simplified to \"*" + var_name + " != '\\0'\"");
}
}

View File

@ -73,6 +73,7 @@ public:
checkOther.checkConstantFunctionParameter(); checkOther.checkConstantFunctionParameter();
checkOther.checkIncompleteStatement(); checkOther.checkIncompleteStatement();
checkOther.unreachableCode(); checkOther.unreachableCode();
checkOther.checkEmptyStringTest();
if (settings->inconclusive) if (settings->inconclusive)
{ {
checkOther.postIncrement(); checkOther.postIncrement();
@ -165,6 +166,8 @@ public:
// haystack.remove(needle); // haystack.remove(needle);
void redundantCondition2(); void redundantCondition2();
/** @brief %Check for inefficient empty string test*/
void checkEmptyStringTest();
// Error messages.. // Error messages..
void cstyleCastError(const Token *tok); void cstyleCastError(const Token *tok);
@ -191,6 +194,7 @@ public:
void zerodivError(const Token *tok); void zerodivError(const Token *tok);
void mathfunctionCallError(const Token *tok, const unsigned int numParam = 1); void mathfunctionCallError(const Token *tok, const unsigned int numParam = 1);
void postIncrementError(const Token *tok, const std::string &var_name, const bool isIncrement); void postIncrementError(const Token *tok, const std::string &var_name, const bool isIncrement);
void emptyStringTestError(const Token *tok, const std::string &var_name, const bool isTestForEmpty);
void getErrorMessages() void getErrorMessages()
{ {
@ -221,6 +225,7 @@ public:
// optimisations // optimisations
postIncrementError(0, "varname", true); postIncrementError(0, "varname", true);
emptyStringTestError(0, "varname", true);
} }
std::string name() const std::string name() const

View File

@ -92,6 +92,8 @@ private:
TEST_CASE(passedByValue); TEST_CASE(passedByValue);
TEST_CASE(mathfunctionCall1); TEST_CASE(mathfunctionCall1);
TEST_CASE(emptyStringTest);
} }
void check(const char code[]) void check(const char code[])
@ -114,6 +116,7 @@ private:
checkOther.checkZeroDivision(); checkOther.checkZeroDivision();
checkOther.unreachableCode(); checkOther.unreachableCode();
checkOther.checkMathFunctions(); checkOther.checkMathFunctions();
checkOther.checkEmptyStringTest();
} }
@ -2366,6 +2369,42 @@ private:
} }
void emptyStringTest()
{
check("void foo()\n"
"{\n"
" if (strlen(str) == 0)\n"
" {\n"
" std::cout << str;\n"
" }\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (possible style) Empty string test can be simplified to \"*str == '\\0'\"\n", errout.str());
check("if (!strlen(str)) { }");
ASSERT_EQUALS("[test.cpp:1]: (possible style) Empty string test can be simplified to \"*str == '\\0'\"\n", errout.str());
check("if (strlen(str) == 0) { }");
ASSERT_EQUALS("[test.cpp:1]: (possible style) Empty string test can be simplified to \"*str == '\\0'\"\n", errout.str());
check("if (strlen(str)) { }");
ASSERT_EQUALS("[test.cpp:1]: (possible style) Non-empty string test can be simplified to \"*str != '\\0'\"\n", errout.str());
check("if (strlen(str) > 0) { }");
ASSERT_EQUALS("[test.cpp:1]: (possible style) Non-empty string test can be simplified to \"*str != '\\0'\"\n", errout.str());
check("if (strlen(str) != 0) { }");
ASSERT_EQUALS("[test.cpp:1]: (possible style) Non-empty string test can be simplified to \"*str != '\\0'\"\n", errout.str());
check("if (0 != strlen(str)) { }");
ASSERT_EQUALS("[test.cpp:1]: (possible style) Non-empty string test can be simplified to \"*str != '\\0'\"\n", errout.str());
check("if (0 == strlen(str)) { }");
ASSERT_EQUALS("[test.cpp:1]: (possible style) Empty string test can be simplified to \"*str == '\\0'\"\n", errout.str());
check("if (0 < strlen(str)) { }");
ASSERT_EQUALS("[test.cpp:1]: (possible style) Non-empty string test can be simplified to \"*str != '\\0'\"\n", errout.str());
}
}; };
REGISTER_TEST(TestOther) REGISTER_TEST(TestOther)