Fix #476 STL Container checks.
Fix #473 Add post increment check for STL objects and Classes.
This commit is contained in:
parent
9136d8cf80
commit
52e2e775b2
|
@ -1141,6 +1141,36 @@ void CheckOther::checkZeroDivision()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CheckOther::postIncrement()
|
||||||
|
{
|
||||||
|
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
||||||
|
{
|
||||||
|
if (!Token::simpleMatch(tok, "for ("))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (const Token *tok2 = tok; tok2; tok2 = tok2->next())
|
||||||
|
{
|
||||||
|
if (Token::Match(tok2, "; %var% ++|-- )"))
|
||||||
|
{
|
||||||
|
// Take a look at the variable declaration
|
||||||
|
const Token *decltok = Token::findmatch(_tokenizer->tokens(), "%varid%", tok2->tokAt(1)->varId());
|
||||||
|
const std::string classDef = std::string("class ") + std::string(decltok->previous()->strAt(0));
|
||||||
|
|
||||||
|
// Is the variable an iterator?
|
||||||
|
if (decltok && Token::Match(decltok->previous(), "iterator|const_iterator"))
|
||||||
|
postIncrementError(tok2, tok2->strAt(1), (std::string("++") == tok2->strAt(2)));
|
||||||
|
// Is the variable a class?
|
||||||
|
else if (Token::findmatch( _tokenizer->tokens(), classDef.c_str() ))
|
||||||
|
postIncrementError(tok2, tok2->strAt(1), (std::string("++") == tok2->strAt(2)));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void CheckOther::cstyleCastError(const Token *tok)
|
void CheckOther::cstyleCastError(const Token *tok)
|
||||||
{
|
{
|
||||||
|
@ -1231,3 +1261,9 @@ void CheckOther::zerodivError(const Token *tok)
|
||||||
{
|
{
|
||||||
reportError(tok, Severity::error, "zerodiv", "Division by zero");
|
reportError(tok, Severity::error, "zerodiv", "Division by zero");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckOther::postIncrementError(const Token *tok, const std::string &var_name, const bool isIncrement)
|
||||||
|
{
|
||||||
|
std::string type = ( isIncrement ? "Incrementing" : "Decrementing" );
|
||||||
|
reportError(tok, Severity::possibleStyle, "postIncrementDecrement", ("Pre-" + type + " variable '" + var_name + "' is preferred to Post-" + type) );
|
||||||
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ public:
|
||||||
checkOther.checkConstantFunctionParameter();
|
checkOther.checkConstantFunctionParameter();
|
||||||
checkOther.checkStructMemberUsage();
|
checkOther.checkStructMemberUsage();
|
||||||
checkOther.checkIncompleteStatement();
|
checkOther.checkIncompleteStatement();
|
||||||
|
checkOther.postIncrement();
|
||||||
}
|
}
|
||||||
|
|
||||||
checkOther.strPlusChar();
|
checkOther.strPlusChar();
|
||||||
|
@ -114,6 +115,9 @@ public:
|
||||||
/** Check zero division*/
|
/** Check zero division*/
|
||||||
void checkZeroDivision();
|
void checkZeroDivision();
|
||||||
|
|
||||||
|
/** Check for post increment/decrement in for loop*/
|
||||||
|
void postIncrement();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void lookupVar(const Token *tok1, const char varname[]);
|
void lookupVar(const Token *tok1, const char varname[]);
|
||||||
|
|
||||||
|
@ -142,6 +146,7 @@ private:
|
||||||
void strPlusChar(const Token *tok);
|
void strPlusChar(const Token *tok);
|
||||||
void nullPointerError(const Token *tok);
|
void nullPointerError(const Token *tok);
|
||||||
void zerodivError(const Token *tok);
|
void zerodivError(const Token *tok);
|
||||||
|
void postIncrementError(const Token *tok, const std::string &var_name, const bool isIncrement);
|
||||||
|
|
||||||
void getErrorMessages()
|
void getErrorMessages()
|
||||||
{
|
{
|
||||||
|
@ -164,6 +169,7 @@ private:
|
||||||
strPlusChar(0);
|
strPlusChar(0);
|
||||||
nullPointerError(0);
|
nullPointerError(0);
|
||||||
zerodivError(0);
|
zerodivError(0);
|
||||||
|
postIncrementError(0, "varname", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name() const
|
std::string name() const
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
#include "tokenize.h"
|
#include "tokenize.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
|
|
||||||
|
// All STL Containers
|
||||||
|
#define STL_CONTAINER_LIST "bitset|deque|list|map|multimap|multiset|priority_queue|queue|set|stack|vector|hash_map|hash_multimap|hash_set"
|
||||||
|
|
||||||
|
|
||||||
// Register this check class (by creating a static instance of it)
|
// Register this check class (by creating a static instance of it)
|
||||||
namespace
|
namespace
|
||||||
|
@ -366,8 +369,10 @@ void CheckStl::stlBoundries()
|
||||||
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
|
||||||
{
|
{
|
||||||
// Declaring iterator..
|
// Declaring iterator..
|
||||||
if (Token::simpleMatch(tok, "list <"))
|
const std::string checkStr = (std::string(STL_CONTAINER_LIST) + " <");
|
||||||
|
if (Token::Match( tok, checkStr.c_str() ))
|
||||||
{
|
{
|
||||||
|
const std::string container_name( tok->strAt(0) );
|
||||||
while (tok && tok->str() != ">")
|
while (tok && tok->str() != ">")
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
if (!tok)
|
if (!tok)
|
||||||
|
@ -393,7 +398,7 @@ void CheckStl::stlBoundries()
|
||||||
}
|
}
|
||||||
else if (tok2->varId() == iteratorid && tok2->next() && tok2->next()->str() == "<")
|
else if (tok2->varId() == iteratorid && tok2->next() && tok2->next()->str() == "<")
|
||||||
{
|
{
|
||||||
stlBoundriesError(tok2);
|
stlBoundriesError(tok2, container_name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -403,7 +408,7 @@ void CheckStl::stlBoundries()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error message for bad boundry usage..
|
// Error message for bad boundry usage..
|
||||||
void CheckStl::stlBoundriesError(const Token *tok)
|
void CheckStl::stlBoundriesError(const Token *tok, const std::string &container_name)
|
||||||
{
|
{
|
||||||
reportError(tok, Severity::error, "stlBoundries", "STL range check should be using != and not < since the order of the pointers isn't guaranteed");
|
reportError(tok, Severity::error, "stlBoundries", container_name + " range check should use != and not < since the order of the pointers isn't guaranteed");
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ private:
|
||||||
void eraseError(const Token *tok);
|
void eraseError(const Token *tok);
|
||||||
void pushbackError(const Token *tok, const std::string &iterator_name);
|
void pushbackError(const Token *tok, const std::string &iterator_name);
|
||||||
void invalidPointerError(const Token *tok, const std::string &pointer_name);
|
void invalidPointerError(const Token *tok, const std::string &pointer_name);
|
||||||
void stlBoundriesError(const Token *tok);
|
void stlBoundriesError(const Token *tok, const std::string &container_name);
|
||||||
|
|
||||||
void getErrorMessages()
|
void getErrorMessages()
|
||||||
{
|
{
|
||||||
|
@ -110,7 +110,7 @@ private:
|
||||||
eraseError(0);
|
eraseError(0);
|
||||||
pushbackError(0, "iterator");
|
pushbackError(0, "iterator");
|
||||||
invalidPointerError(0, "pointer");
|
invalidPointerError(0, "pointer");
|
||||||
stlBoundriesError(0);
|
stlBoundriesError(0, "container");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string name() const
|
std::string name() const
|
||||||
|
|
|
@ -62,6 +62,9 @@ private:
|
||||||
TEST_CASE(nullpointer4);
|
TEST_CASE(nullpointer4);
|
||||||
|
|
||||||
TEST_CASE(oldStylePointerCast);
|
TEST_CASE(oldStylePointerCast);
|
||||||
|
|
||||||
|
TEST_CASE(postIncrementDecrementStl);
|
||||||
|
TEST_CASE(postIncrementDecrementClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char code[])
|
void check(const char code[])
|
||||||
|
@ -616,6 +619,64 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void checkpostIncrementDecrement(const char code[])
|
||||||
|
{
|
||||||
|
// Tokenize..
|
||||||
|
Tokenizer tokenizer;
|
||||||
|
std::istringstream istr(code);
|
||||||
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
tokenizer.setVarId();
|
||||||
|
|
||||||
|
// Clear the error buffer..
|
||||||
|
errout.str("");
|
||||||
|
|
||||||
|
// Check for redundant code..
|
||||||
|
Settings settings;
|
||||||
|
settings._checkCodingStyle = true;
|
||||||
|
CheckOther checkOther(&tokenizer, &settings, this);
|
||||||
|
checkOther.postIncrement();
|
||||||
|
}
|
||||||
|
|
||||||
|
void postIncrementDecrementStl()
|
||||||
|
{
|
||||||
|
checkpostIncrementDecrement("void f1()\n"
|
||||||
|
"{\n"
|
||||||
|
" std::list<int>::iterator it;\n"
|
||||||
|
" for (it = ab.begin(); it != ab.end(); it++)\n"
|
||||||
|
" ;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (possible style) Pre-Incrementing variable 'it' is preferred to Post-Incrementing\n", errout.str());
|
||||||
|
|
||||||
|
checkpostIncrementDecrement("void f2()\n"
|
||||||
|
"{\n"
|
||||||
|
" std::list<int>::iterator it;\n"
|
||||||
|
" for (it = ab.end(); it != ab.begin(); it--)\n"
|
||||||
|
" ;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (possible style) Pre-Decrementing variable 'it' is preferred to Post-Decrementing\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void postIncrementDecrementClass()
|
||||||
|
{
|
||||||
|
checkpostIncrementDecrement("class TestClass;\n"
|
||||||
|
"void f1()\n"
|
||||||
|
"{\n"
|
||||||
|
" TestClass tClass;\n"
|
||||||
|
" for (tClass = TestClass.begin(); tClass != TestClass.end(); tClass++)\n"
|
||||||
|
" ;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (possible style) Pre-Incrementing variable 'tClass' is preferred to Post-Incrementing\n", errout.str());
|
||||||
|
|
||||||
|
checkpostIncrementDecrement("class TestClass;\n"
|
||||||
|
"void f1()\n"
|
||||||
|
"{\n"
|
||||||
|
" TestClass tClass;\n"
|
||||||
|
" for (tClass = TestClass.end(); tClass != TestClass.begin(); tClass--)\n"
|
||||||
|
" ;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (possible style) Pre-Decrementing variable 'tClass' is preferred to Post-Decrementing\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestOther)
|
REGISTER_TEST(TestOther)
|
||||||
|
|
|
@ -375,23 +375,27 @@ private:
|
||||||
|
|
||||||
void stlBoundries1()
|
void stlBoundries1()
|
||||||
{
|
{
|
||||||
check("void f()\n"
|
const int STL_CONTAINER_LIST = 10;
|
||||||
"{\n"
|
const std::string stlCont[STL_CONTAINER_LIST] =
|
||||||
" std::list<int>::iterator it;\n"
|
{"vector", "deque", "list", "set", "multiset", "map",
|
||||||
" for (it = ab.begin(); it < ab.end(); ++it)\n"
|
"multimap", "hash_map", "hash_multimap", "hash_set"};
|
||||||
" ;\n"
|
|
||||||
"}\n");
|
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (error) STL range check should be using != and not < since the order of the pointers isn't guaranteed\n", errout.str());
|
|
||||||
|
|
||||||
check("void f()\n"
|
for(int i = 0; i < STL_CONTAINER_LIST; ++i)
|
||||||
"{\n"
|
{
|
||||||
" std::vector<int>::iterator it;\n"
|
const std::string checkStr( "void f()\n"
|
||||||
" for (it = ab.begin(); it < ab.end(); ++it)\n"
|
"{\n"
|
||||||
" ;\n"
|
" std::" + stlCont[i] + "<int>::iterator it;\n"
|
||||||
"}\n");
|
" for (it = ab.begin(); it < ab.end(); ++it)\n"
|
||||||
ASSERT_EQUALS("", errout.str());
|
" ;\n"
|
||||||
|
"}\n" );
|
||||||
|
|
||||||
|
check( checkStr.c_str() );
|
||||||
|
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (error) " + stlCont[i] + " range check should use != and not < since the order of the pointers isn't guaranteed\n", errout.str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestStl)
|
REGISTER_TEST(TestStl)
|
||||||
|
|
Loading…
Reference in New Issue