Partial fix for #13 - detect simple cases of member functions that can be const

This commit is contained in:
Daniel Marjamäki 2010-01-23 09:19:22 +01:00
parent 037ecffc34
commit 35c303943f
3 changed files with 116 additions and 1 deletions

View File

@ -1398,6 +1398,85 @@ void CheckClass::thisSubtraction()
}
}
void CheckClass::checkConst()
{
for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())
{
if (Token::Match(tok, "class %var% :|{"))
{
// get class name..
const std::string classname(tok->strAt(1));
// goto initial {'
while (tok && tok->str() != "{")
tok = tok->next();
if (!tok)
break;
// parse in this class definition to see if there are any simple getter functions
for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next())
{
if (tok2->str() == "{")
tok2 = tok2->link();
else if (tok2->str() == "}")
break;
// member function?
if (Token::Match(tok2, "[;}] %type% %var% ("))
{
// get function name
const std::string functionName(tok2->strAt(2));
// goto the ')'
tok2 = tok2->tokAt(3)->link();
if (!tok2)
break;
// is this function implemented inline?
if (Token::simpleMatch(tok2, ") {"))
{
// if the function doesn't have any assignment nor function call,
// it can be a const function..
unsigned int indentlevel = 0;
bool isconst = true;
for (const Token *tok3 = tok2; tok3; tok3 = tok3->next())
{
if (tok3->str() == "{")
++indentlevel;
else if (tok3->str() == "}")
{
if (indentlevel <= 1)
break;
--indentlevel;
}
else if (tok3->str() == "=" ||
Token::Match(tok, "%var% ("))
{
isconst = false;
break;
}
}
// nothing non-const was found. write error..
if (isconst)
checkConstError(tok2, classname, functionName);
}
}
}
}
}
}
void CheckClass::checkConstError(const Token *tok, const std::string &classname, const std::string &funcname)
{
reportError(tok, Severity::style, "functionConst", "The function '" + classname + "::" + funcname + "' can be const");
}
void CheckClass::noConstructorError(const Token *tok, const std::string &classname, bool isStruct)
{
reportError(tok, Severity::style, "noConstructor", "The " + std::string(isStruct ? "struct" : "class") + " '" + classname + "' has no constructor. Member variables not initialized.");

View File

@ -96,6 +96,9 @@ public:
/** @brief warn for "this-x". The indented code may be "this->x" */
void thisSubtraction();
/** @brief can member function be const? */
void checkConst();
private:
/** @brief Information about a member variable. Used when checking for uninitialized variables */
@ -161,6 +164,8 @@ private:
void operatorEqRetRefThisError(const Token *tok);
void operatorEqToSelfError(const Token *tok);
void checkConstError(const Token *tok, const std::string &classname, const std::string &funcname);
void getErrorMessages()
{
noConstructorError(0, "classname", false);
@ -174,6 +179,7 @@ private:
thisSubtractionError(0);
operatorEqRetRefThisError(0);
operatorEqToSelfError(0);
checkConstError(0, "class", "function");
}
std::string name() const
@ -189,7 +195,8 @@ private:
"* [[CheckMemset|Warn if memset, memcpy etc are used on a class]]\n"
"* If it's a base class, check that the destructor is virtual\n"
"* The operator= should return a constant reference to itself\n"
"* Are there unused private functions\n";
"* Are there unused private functions\n"
"* Constness for member functions\n";
}
};
/// @}

View File

@ -78,6 +78,9 @@ private:
TEST_CASE(memsetOnClass);
TEST_CASE(this_subtraction); // warn about "this-x"
// can member function be made const
TEST_CASE(const1);
}
// Check the operator Equal
@ -1501,6 +1504,32 @@ private:
ASSERT_EQUALS("[test.cpp:2]: (possible style) Suspicious pointer subtraction\n"
"[test.cpp:3]: (possible style) Suspicious pointer subtraction\n", errout.str());
}
void checkConst(const char code[])
{
// Tokenize..
Tokenizer tokenizer;
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.simplifyTokenList();
// Clear the error log
errout.str("");
// Check..
Settings settings;
CheckClass checkClass(&tokenizer, &settings, this);
checkClass.checkConst();
}
void const1()
{
checkConst("class Fred {\n"
" int a;\n"
" int getA() { return a; }\n"
"};\n");
ASSERT_EQUALS("[test.cpp:3]: (style) The function 'Fred::getA' can be const\n", errout.str());
}
};
REGISTER_TEST(TestClass)