initial simplistic implementation of switchCaseFallThrough
This commit is contained in:
parent
d7a6e729b8
commit
93ea774484
|
@ -306,6 +306,46 @@ void CheckOther::checkRedundantAssignmentInSwitch()
|
|||
}
|
||||
|
||||
|
||||
void CheckOther::checkSwitchCaseFallThrough()
|
||||
{
|
||||
const char switchPattern[] = "switch ( %any% ) { case";
|
||||
//const char breakPattern[] = "break|continue|return|exit|goto";
|
||||
//const char functionPattern[] = "%var% (";
|
||||
// nested switch
|
||||
|
||||
// Find the beginning of a switch. E.g.:
|
||||
// switch (var) { ...
|
||||
const Token *tok = Token::findmatch(_tokenizer->tokens(), switchPattern);
|
||||
while (tok)
|
||||
{
|
||||
|
||||
// Check the contents of the switch statement
|
||||
for (const Token *tok2 = tok->tokAt(6); tok2; tok2 = tok2->next())
|
||||
{
|
||||
if (Token::Match(tok2, switchPattern))
|
||||
{
|
||||
tok2 = tok2->tokAt(4)->link()->previous();
|
||||
}
|
||||
else if (tok2->str() == "case")
|
||||
{
|
||||
if (!Token::Match(tok2->previous()->previous(), "break"))
|
||||
{
|
||||
switchCaseFallThrough(tok2);
|
||||
}
|
||||
}
|
||||
else if (tok2->str() == "}")
|
||||
{
|
||||
// End of the switch block
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tok = Token::findmatch(tok->next(), switchPattern);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// int x = 1;
|
||||
// x = x; // <- redundant assignment to self
|
||||
|
@ -2998,6 +3038,12 @@ void CheckOther::redundantAssignmentInSwitchError(const Token *tok, const std::s
|
|||
"redundantAssignInSwitch", "Redundant assignment of \"" + varname + "\" in switch");
|
||||
}
|
||||
|
||||
void CheckOther::switchCaseFallThrough(const Token *tok)
|
||||
{
|
||||
reportError(tok, Severity::warning,
|
||||
"switchCaseFallThrough", "Switch falls through case without comment");
|
||||
}
|
||||
|
||||
void CheckOther::selfAssignmentError(const Token *tok, const std::string &varname)
|
||||
{
|
||||
reportError(tok, Severity::warning,
|
||||
|
|
|
@ -61,6 +61,7 @@ public:
|
|||
checkOther.sizeofsizeof();
|
||||
checkOther.sizeofCalculation();
|
||||
checkOther.checkRedundantAssignmentInSwitch();
|
||||
checkOther.checkSwitchCaseFallThrough();
|
||||
checkOther.checkAssignmentInAssert();
|
||||
checkOther.checkSizeofForArrayParameter();
|
||||
checkOther.checkSelfAssignment();
|
||||
|
@ -162,6 +163,9 @@ public:
|
|||
/** @brief %Check for assigning to the same variable twice in a switch statement*/
|
||||
void checkRedundantAssignmentInSwitch();
|
||||
|
||||
/** @brief %Check for switch case fall through without comment */
|
||||
void checkSwitchCaseFallThrough();
|
||||
|
||||
/** @brief %Check for assigning a variable to itself*/
|
||||
void checkSelfAssignment();
|
||||
|
||||
|
@ -209,6 +213,7 @@ public:
|
|||
void mathfunctionCallError(const Token *tok, const unsigned int numParam = 1);
|
||||
void fflushOnInputStreamError(const Token *tok, const std::string &varname);
|
||||
void redundantAssignmentInSwitchError(const Token *tok, const std::string &varname);
|
||||
void switchCaseFallThrough(const Token *tok);
|
||||
void selfAssignmentError(const Token *tok, const std::string &varname);
|
||||
void assignmentInAssertError(const Token *tok, const std::string &varname);
|
||||
void incorrectLogicOperatorError(const Token *tok);
|
||||
|
@ -247,6 +252,7 @@ public:
|
|||
c.sizeofsizeofError(0);
|
||||
c.sizeofCalculationError(0);
|
||||
c.redundantAssignmentInSwitchError(0, "varname");
|
||||
c.switchCaseFallThrough(0);
|
||||
c.selfAssignmentError(0, "varname");
|
||||
c.assignmentInAssertError(0, "varname");
|
||||
c.invalidScanfError(0);
|
||||
|
|
|
@ -377,10 +377,10 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
|
|||
i = str.find('\n', i);
|
||||
if (i == std::string::npos)
|
||||
break;
|
||||
std::string comment(str, commentStart, i - commentStart);
|
||||
|
||||
if (settings && settings->_inlineSuppressions)
|
||||
{
|
||||
std::string comment(str, commentStart, i - commentStart);
|
||||
std::istringstream iss(comment);
|
||||
std::string word;
|
||||
iss >> word;
|
||||
|
@ -392,6 +392,11 @@ std::string Preprocessor::removeComments(const std::string &str, const std::stri
|
|||
}
|
||||
}
|
||||
|
||||
if (comment.find("fall through") != std::string::npos)
|
||||
{
|
||||
suppressionIDs.push_back("switchCaseFallThrough");
|
||||
}
|
||||
|
||||
code << "\n";
|
||||
previous = '\n';
|
||||
++lineno;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "preprocessor.h"
|
||||
#include "tokenize.h"
|
||||
#include "checkother.h"
|
||||
#include "testsuite.h"
|
||||
|
@ -74,6 +75,7 @@ private:
|
|||
TEST_CASE(sizeofCalculation);
|
||||
|
||||
TEST_CASE(switchRedundantAssignmentTest);
|
||||
TEST_CASE(switchFallThroughCase);
|
||||
|
||||
TEST_CASE(selfAssignment);
|
||||
TEST_CASE(testScanf1);
|
||||
|
@ -148,6 +150,60 @@ private:
|
|||
checkOther.checkComparisonOfBoolWithInt();
|
||||
}
|
||||
|
||||
class SimpleSuppressor: public ErrorLogger
|
||||
{
|
||||
public:
|
||||
SimpleSuppressor(Settings &settings, ErrorLogger *next)
|
||||
: _settings(settings), _next(next)
|
||||
{ }
|
||||
virtual void reportOut(const std::string &outmsg)
|
||||
{
|
||||
_next->reportOut(outmsg);
|
||||
}
|
||||
virtual void reportErr(const ErrorLogger::ErrorMessage &msg)
|
||||
{
|
||||
if (!msg._callStack.empty() && !_settings.nomsg.isSuppressed(msg._id, msg._callStack.begin()->getfile(), msg._callStack.begin()->line))
|
||||
_next->reportErr(msg);
|
||||
}
|
||||
virtual void reportStatus(unsigned int index, unsigned int max)
|
||||
{
|
||||
_next->reportStatus(index, max);
|
||||
}
|
||||
private:
|
||||
Settings &_settings;
|
||||
ErrorLogger *_next;
|
||||
};
|
||||
|
||||
void check_preprocess_suppress(const char precode[], const char *filename = NULL)
|
||||
{
|
||||
// Clear the error buffer..
|
||||
errout.str("");
|
||||
|
||||
if (filename == NULL)
|
||||
filename = "test.cpp";
|
||||
|
||||
Settings settings;
|
||||
settings._checkCodingStyle = true;
|
||||
|
||||
// Preprocess file..
|
||||
Preprocessor preprocessor(&settings, this);
|
||||
std::list<std::string> configurations;
|
||||
std::string filedata = "";
|
||||
std::istringstream fin(precode);
|
||||
preprocessor.preprocess(fin, filedata, configurations, filename, settings._includePaths);
|
||||
SimpleSuppressor logger(settings, this);
|
||||
const std::string code = Preprocessor::getcode(filedata, "", filename, &settings, &logger);
|
||||
|
||||
// Tokenize..
|
||||
Tokenizer tokenizer(&settings, &logger);
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, filename);
|
||||
|
||||
// Check..
|
||||
CheckOther checkOther(&tokenizer, &settings, &logger);
|
||||
checkOther.checkSwitchCaseFallThrough();
|
||||
}
|
||||
|
||||
|
||||
void zeroDiv1()
|
||||
{
|
||||
|
@ -1146,6 +1202,56 @@ private:
|
|||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void switchFallThroughCase()
|
||||
{
|
||||
check_preprocess_suppress(
|
||||
"void foo() {\n"
|
||||
" switch (a) {\n"
|
||||
" case 1:\n"
|
||||
" break;\n"
|
||||
" case 2:\n"
|
||||
" break;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check_preprocess_suppress(
|
||||
"void foo() {\n"
|
||||
" switch (a) {\n"
|
||||
" case 1:\n"
|
||||
" g();\n"
|
||||
" case 2:\n"
|
||||
" break;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (warning) Switch falls through case without comment\n", errout.str());
|
||||
|
||||
check_preprocess_suppress(
|
||||
"void foo() {\n"
|
||||
" switch (a) {\n"
|
||||
" case 1:\n"
|
||||
" g();\n"
|
||||
" // fall through\n"
|
||||
" case 2:\n"
|
||||
" break;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check_preprocess_suppress(
|
||||
"void foo() {\n"
|
||||
" switch (a) {\n"
|
||||
" case 1:\n"
|
||||
" g();\n"
|
||||
" break;\n"
|
||||
" // fall through\n"
|
||||
" case 2:\n"
|
||||
" break;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void selfAssignment()
|
||||
{
|
||||
check("void foo()\n"
|
||||
|
|
Loading…
Reference in New Issue