Fixed #1883 (false positive: (style) The function 'A::SetPos' can be const)

This commit is contained in:
Robert Reif 2010-07-19 13:16:11 +02:00 committed by Daniel Marjamäki
parent d4d0bc050a
commit 4cf92992a8
3 changed files with 89 additions and 8 deletions

View File

@ -1992,7 +1992,7 @@ void CheckClass::checkConst()
}
// if nothing non-const was found. write error..
if (checkConstFunc(classname, varlist, paramEnd))
if (checkConstFunc(info.className, info.derivedFrom, varlist, paramEnd))
{
for (int i = nestInfo.size() - 2; i >= 0; i--)
classname = std::string(nestInfo[i].className + "::" + classname);
@ -2027,7 +2027,7 @@ void CheckClass::checkConst()
if (sameFunc(namespaceLevel, tok2, paramEnd))
{
// if nothing non-const was found. write error..
if (checkConstFunc(classname, varlist, paramEnd))
if (checkConstFunc(info.className, info.derivedFrom, varlist, paramEnd))
{
for (int k = nestInfo.size() - 2; k >= 0; k--)
classname = std::string(nestInfo[k].className + "::" + classname);
@ -2254,7 +2254,7 @@ bool CheckClass::isMemberFunc(const Token *tok)
return false;
}
bool CheckClass::isMemberVar(const std::string &classname, const Var *varlist, const Token *tok)
bool CheckClass::isMemberVar(const std::string &classname, const std::vector<std::string> &derivedFrom, const Var *varlist, const Token *tok)
{
while (tok->previous() && !Token::Match(tok->previous(), "}|{|;|public:|protected:|private:|return|:|?"))
{
@ -2282,10 +2282,71 @@ bool CheckClass::isMemberVar(const std::string &classname, const Var *varlist, c
}
}
// not found in this class
if (!derivedFrom.empty())
{
// check each base class
for (unsigned int i = 0; i < derivedFrom.size(); ++i)
{
std::string className;
if (derivedFrom[i].find("::") != std::string::npos)
{
/** @todo handle nested base classes and namespaces */
}
else
className = derivedFrom[i];
std::string classPattern = std::string("class|struct ") + className + std::string(" {|:");
// find the base class
const Token *classToken = Token::findmatch(_tokenizer->tokens(), classPattern.c_str());
// find the function in the base class
if (classToken)
{
std::vector<std::string> baseList;
const Token * tok1 = classToken;
while (tok1->str() != "{")
{
// check for base classes
if (Token::Match(tok1, ":|, public|protected|private"))
{
// jump to base class name
tok1 = tok1->tokAt(2);
std::string base;
// handle nested base classea and namespacess
while (Token::Match(tok1, "%var% ::"))
{
base += tok1->str();
base += " :: ";
tok1 = tok1->tokAt(2);
}
base += tok1->str();
// save pattern for base class name
baseList.push_back(base);
}
tok1 = tok1->next();
}
// Get class variables...
Var *varlist1 = getVarList(classToken);
if (isMemberVar(classToken->next()->str(), baseList, varlist1, tok))
return true;
}
}
}
return false;
}
bool CheckClass::checkConstFunc(const std::string &classname, const Var *varlist, const Token *tok)
bool CheckClass::checkConstFunc(const std::string &classname, const std::vector<std::string> &derivedFrom, const Var *varlist, const Token *tok)
{
// if the function doesn't have any assignment nor function call,
// it can be a const function..
@ -2307,7 +2368,7 @@ bool CheckClass::checkConstFunc(const std::string &classname, const Var *varlist
(tok1->str().find("=") == 1 &&
tok1->str().find_first_of("<!>") == std::string::npos))
{
if (isMemberVar(classname, varlist, tok1->previous()))
if (isMemberVar(classname, derivedFrom, varlist, tok1->previous()))
{
isconst = false;
break;
@ -2315,7 +2376,7 @@ bool CheckClass::checkConstFunc(const std::string &classname, const Var *varlist
}
// streaming: <<
else if (tok1->str() == "<<" && isMemberVar(classname, varlist, tok1->previous()))
else if (tok1->str() == "<<" && isMemberVar(classname, derivedFrom, varlist, tok1->previous()))
{
isconst = false;
break;

View File

@ -165,8 +165,8 @@ private:
bool sameFunc(int nest, const Token *firstEnd, const Token *secondEnd);
bool isMemberFunc(const Token *tok);
bool isMemberVar(const std::string &classname, const Var *varlist, const Token *tok);
bool checkConstFunc(const std::string &classname, const Var *varlist, const Token *tok);
bool isMemberVar(const std::string &classname, const std::vector<std::string> &derivedFrom, const Var *varlist, const Token *tok);
bool checkConstFunc(const std::string &classname, const std::vector<std::string> &derivedFrom, const Var *varlist, const Token *tok);
/** @brief check if this function is virtual in the base classes */
bool isVirtual(const std::vector<std::string> &derivedFrom, const Token *functionToken) const;

View File

@ -130,6 +130,7 @@ private:
TEST_CASE(const25); // ticket #1724
TEST_CASE(const26); // ticket #1847
TEST_CASE(const27); // ticket #1882
TEST_CASE(const28); // ticket #1883
TEST_CASE(constoperator1); // operator< can often be const
TEST_CASE(constoperator2); // operator<<
TEST_CASE(constincdec); // increment/decrement => non-const
@ -3612,6 +3613,25 @@ private:
ASSERT_EQUALS("", errout.str());
}
void const28() // ticket #1883
{
checkConst("class P {\n"
"public:\n"
" P() { x=0.0; y=0.0; }\n"
" double x,y;\n"
"};\n"
"class A : public P {\n"
"public:\n"
" A():P(){}\n"
" void SetPos(double xPos, double yPos) {\n"
" x=xPos;\n"
" y=yPos;\n"
" }\n"
"};\n"
);
ASSERT_EQUALS("", errout.str());
}
void const27() // ticket #1882
{
checkConst("class A {\n"