Fixed #2627 (switch case fall through: redundant strcpy)
This commit is contained in:
parent
91d7621994
commit
82366918ff
|
@ -482,6 +482,7 @@ void CheckOther::checkRedundantAssignmentInSwitch()
|
||||||
|
|
||||||
// Check the contents of the switch statement
|
// Check the contents of the switch statement
|
||||||
std::map<unsigned int, const Token*> varsAssigned;
|
std::map<unsigned int, const Token*> varsAssigned;
|
||||||
|
std::map<unsigned int, const Token*> stringsCopied;
|
||||||
int indentLevel = 0;
|
int indentLevel = 0;
|
||||||
for (const Token *tok2 = tok->tokAt(5); tok2; tok2 = tok2->next())
|
for (const Token *tok2 = tok->tokAt(5); tok2; tok2 = tok2->next())
|
||||||
{
|
{
|
||||||
|
@ -496,9 +497,17 @@ void CheckOther::checkRedundantAssignmentInSwitch()
|
||||||
for (const Token* tok3 = tok2; tok3 != endOfConditional; tok3 = tok3->next())
|
for (const Token* tok3 = tok2; tok3 != endOfConditional; tok3 = tok3->next())
|
||||||
{
|
{
|
||||||
if (tok3->varId() != 0)
|
if (tok3->varId() != 0)
|
||||||
|
{
|
||||||
varsAssigned.erase(tok3->varId());
|
varsAssigned.erase(tok3->varId());
|
||||||
|
stringsCopied.erase(tok3->varId());
|
||||||
|
}
|
||||||
else if (Token::Match(tok3, functionPattern) || Token::Match(tok3, breakPattern))
|
else if (Token::Match(tok3, functionPattern) || Token::Match(tok3, breakPattern))
|
||||||
|
{
|
||||||
varsAssigned.clear();
|
varsAssigned.clear();
|
||||||
|
|
||||||
|
if (tok3->str() != "strcpy" && tok3->str() != "strncpy")
|
||||||
|
stringsCopied.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
tok2 = endOfConditional;
|
tok2 = endOfConditional;
|
||||||
}
|
}
|
||||||
|
@ -524,6 +533,19 @@ void CheckOther::checkRedundantAssignmentInSwitch()
|
||||||
varsAssigned[tok2->varId()] = tok2;
|
varsAssigned[tok2->varId()] = tok2;
|
||||||
else
|
else
|
||||||
redundantAssignmentInSwitchError(i->second, i->second->str());
|
redundantAssignmentInSwitchError(i->second, i->second->str());
|
||||||
|
|
||||||
|
stringsCopied.erase(tok2->varId());
|
||||||
|
}
|
||||||
|
// String copy. Report an error if it's copied to twice before a break. E.g.:
|
||||||
|
// case 3: strcpy(str, "a"); // <== redundant
|
||||||
|
// case 4: strcpy(str, "b");
|
||||||
|
else if (Token::Match(tok2->previous(), ";|{|}|: strcpy|strncpy ( %var% ,") && tok2->tokAt(2)->varId() != 0)
|
||||||
|
{
|
||||||
|
std::map<unsigned int, const Token*>::iterator i = stringsCopied.find(tok2->tokAt(2)->varId());
|
||||||
|
if (i == stringsCopied.end())
|
||||||
|
stringsCopied[tok2->tokAt(2)->varId()] = tok2->tokAt(2);
|
||||||
|
else
|
||||||
|
redundantStrcpyInSwitchError(i->second, i->second->str());
|
||||||
}
|
}
|
||||||
// Not a simple assignment so there may be good reason if this variable is assigned to twice. E.g.:
|
// Not a simple assignment so there may be good reason if this variable is assigned to twice. E.g.:
|
||||||
// case 3: b = 1;
|
// case 3: b = 1;
|
||||||
|
@ -534,8 +556,13 @@ void CheckOther::checkRedundantAssignmentInSwitch()
|
||||||
// Reset our record of assignments if there is a break or function call. E.g.:
|
// Reset our record of assignments if there is a break or function call. E.g.:
|
||||||
// case 3: b = 1; break;
|
// case 3: b = 1; break;
|
||||||
if (Token::Match(tok2, functionPattern) || Token::Match(tok2, breakPattern))
|
if (Token::Match(tok2, functionPattern) || Token::Match(tok2, breakPattern))
|
||||||
|
{
|
||||||
varsAssigned.clear();
|
varsAssigned.clear();
|
||||||
|
|
||||||
|
if (tok2->str() != "strcpy" && tok2->str() != "strncpy")
|
||||||
|
stringsCopied.clear();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tok = Token::findmatch(tok->next(), switchPattern);
|
tok = Token::findmatch(tok->next(), switchPattern);
|
||||||
|
@ -548,6 +575,14 @@ void CheckOther::redundantAssignmentInSwitchError(const Token *tok, const std::s
|
||||||
"redundantAssignInSwitch", "Redundant assignment of \"" + varname + "\" in switch");
|
"redundantAssignInSwitch", "Redundant assignment of \"" + varname + "\" in switch");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckOther::redundantStrcpyInSwitchError(const Token *tok, const std::string &varname)
|
||||||
|
{
|
||||||
|
reportError(tok, Severity::warning,
|
||||||
|
"redundantStrcpyInSwitch",
|
||||||
|
"Switch case fall-through. Redundant strcpy of \"" + varname + "\".\n"
|
||||||
|
"Switch case fall-through. Redundant strcpy of \"" + varname + "\". The string is overwritten in a later case block.");
|
||||||
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
void CheckOther::checkSwitchCaseFallThrough()
|
void CheckOther::checkSwitchCaseFallThrough()
|
||||||
|
|
|
@ -252,6 +252,7 @@ public:
|
||||||
void mathfunctionCallError(const Token *tok, const unsigned int numParam = 1);
|
void mathfunctionCallError(const Token *tok, const unsigned int numParam = 1);
|
||||||
void fflushOnInputStreamError(const Token *tok, const std::string &varname);
|
void fflushOnInputStreamError(const Token *tok, const std::string &varname);
|
||||||
void redundantAssignmentInSwitchError(const Token *tok, const std::string &varname);
|
void redundantAssignmentInSwitchError(const Token *tok, const std::string &varname);
|
||||||
|
void redundantStrcpyInSwitchError(const Token *tok, const std::string &varname);
|
||||||
void switchCaseFallThrough(const Token *tok);
|
void switchCaseFallThrough(const Token *tok);
|
||||||
void selfAssignmentError(const Token *tok, const std::string &varname);
|
void selfAssignmentError(const Token *tok, const std::string &varname);
|
||||||
void assignmentInAssertError(const Token *tok, const std::string &varname);
|
void assignmentInAssertError(const Token *tok, const std::string &varname);
|
||||||
|
@ -362,6 +363,7 @@ public:
|
||||||
"* condition that is always true/false\n"
|
"* condition that is always true/false\n"
|
||||||
"* unusal pointer arithmetic. For example: \"abc\" + 'd'\n"
|
"* unusal pointer arithmetic. For example: \"abc\" + 'd'\n"
|
||||||
"* redundant assignment in a switch statement\n"
|
"* redundant assignment in a switch statement\n"
|
||||||
|
"* redundant strcpy in a switch statement\n"
|
||||||
"* look for 'sizeof sizeof ..'\n"
|
"* look for 'sizeof sizeof ..'\n"
|
||||||
"* look for calculations inside sizeof()\n"
|
"* look for calculations inside sizeof()\n"
|
||||||
"* assignment of a variable to itself\n"
|
"* assignment of a variable to itself\n"
|
||||||
|
|
|
@ -1305,6 +1305,72 @@ private:
|
||||||
" }\n"
|
" }\n"
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void foo(char *str, int a)\n"
|
||||||
|
"{\n"
|
||||||
|
" switch (a)\n"
|
||||||
|
" {\n"
|
||||||
|
" case 2:\n"
|
||||||
|
" strcpy(str, \"a'\");\n"
|
||||||
|
" case 3:\n"
|
||||||
|
" strcpy(str, \"b'\");\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:6]: (warning) Switch case fall-through. Redundant strcpy of \"str\".\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo(char *str, int a)\n"
|
||||||
|
"{\n"
|
||||||
|
" switch (a)\n"
|
||||||
|
" {\n"
|
||||||
|
" case 2:\n"
|
||||||
|
" strncpy(str, \"a'\");\n"
|
||||||
|
" case 3:\n"
|
||||||
|
" strncpy(str, \"b'\");\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:6]: (warning) Switch case fall-through. Redundant strcpy of \"str\".\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo(char *str, int a)\n"
|
||||||
|
"{\n"
|
||||||
|
" int z = 0;\n"
|
||||||
|
" switch (a)\n"
|
||||||
|
" {\n"
|
||||||
|
" case 2:\n"
|
||||||
|
" strcpy(str, \"a'\");\n"
|
||||||
|
" z++;\n"
|
||||||
|
" case 3:\n"
|
||||||
|
" strcpy(str, \"b'\");\n"
|
||||||
|
" z++;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:7]: (warning) Switch case fall-through. Redundant strcpy of \"str\".\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo(char *str, int a)\n"
|
||||||
|
"{\n"
|
||||||
|
" switch (a)\n"
|
||||||
|
" {\n"
|
||||||
|
" case 2:\n"
|
||||||
|
" strcpy(str, \"a'\");\n"
|
||||||
|
" break;\n"
|
||||||
|
" case 3:\n"
|
||||||
|
" strcpy(str, \"b'\");\n"
|
||||||
|
" break;\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("void foo(char *str, int a)\n"
|
||||||
|
"{\n"
|
||||||
|
" switch (a)\n"
|
||||||
|
" {\n"
|
||||||
|
" case 2:\n"
|
||||||
|
" strcpy(str, \"a'\");\n"
|
||||||
|
" printf(str);\n"
|
||||||
|
" case 3:\n"
|
||||||
|
" strcpy(str, \"b'\");\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void switchFallThroughCase()
|
void switchFallThroughCase()
|
||||||
|
|
Loading…
Reference in New Issue