uninitialized class members: better handling of nested classes

This commit is contained in:
Robert Reif 2010-07-18 20:43:51 +02:00 committed by Daniel Marjamäki
parent 9063983e2b
commit 689de10abf
3 changed files with 100 additions and 5 deletions

View File

@ -485,7 +485,7 @@ struct Constructor
bool isCopyConstructor; bool isCopyConstructor;
}; };
static bool argsMatch(const Token *first, const Token *second) static bool argsMatch(const Token *first, const Token *second, const std::string &path, unsigned int depth)
{ {
bool match = false; bool match = false;
while (first->str() == second->str()) while (first->str() == second->str())
@ -528,6 +528,35 @@ static bool argsMatch(const Token *first, const Token *second)
first = first->tokAt(2); first = first->tokAt(2);
} }
// variable with class path
else if (depth && Token::Match(first->next(), "%var%"))
{
std::string param = path + first->next()->str();
if (Token::Match(second->next(), param.c_str()))
{
second = second->tokAt(depth * 2);
}
else if (depth > 1)
{
std::string short_path = path;
// remove last " :: "
short_path.resize(short_path.size() - 4);
// remove last name
while (!short_path.empty() && short_path[short_path.size() - 1] != ' ')
short_path.resize(short_path.size() - 1);
param = short_path + first->next()->str();
if (Token::Match(second->next(), param.c_str()))
{
second = second->tokAt((depth - 1) * 2);
}
}
}
first = first->next(); first = first->next();
second = second->next(); second = second->next();
} }
@ -630,6 +659,8 @@ void CheckClass::constructors()
int stack_index = spaceInfo.size() - 1; int stack_index = spaceInfo.size() - 1;
std::string classPattern; std::string classPattern;
std::string classPath;
std::string searchPattern;
int offset1, offset2; int offset1, offset2;
if (operatorEqual) if (operatorEqual)
{ {
@ -643,20 +674,23 @@ void CheckClass::constructors()
} }
bool hasBody = false; bool hasBody = false;
unsigned int depth = 0;
while (!hasBody && stack_index >= 0) while (!hasBody && stack_index >= 0)
{ {
classPattern = spaceInfo[stack_index].className + std::string(" :: ") + classPattern; classPath = spaceInfo[stack_index].className + std::string(" :: ") + classPath;
searchPattern = classPath + classPattern;
offset2 += 2; offset2 += 2;
depth++;
// start looking at end of class // start looking at end of class
const Token *constructor_token = spaceInfo[stack_index].classEnd; const Token *constructor_token = spaceInfo[stack_index].classEnd;
while ((constructor_token = Token::findmatch(constructor_token, classPattern.c_str())) != NULL) while ((constructor_token = Token::findmatch(constructor_token, searchPattern.c_str())) != NULL)
{ {
// skip destructor and other classes // skip destructor and other classes
if (!Token::Match(constructor_token->previous(), "~|::")) if (!Token::Match(constructor_token->previous(), "~|::"))
{ {
if (argsMatch(tok->tokAt(offset1), constructor_token->tokAt(offset2))) if (argsMatch(tok->tokAt(offset1), constructor_token->tokAt(offset2), classPath, depth))
{ {
constructorList.push_back(Constructor(constructor_token, access, true, operatorEqual, copyConstructor)); constructorList.push_back(Constructor(constructor_token, access, true, operatorEqual, copyConstructor));
@ -1774,7 +1808,7 @@ bool CheckClass::isVirtual(const std::vector<std::string> &derivedFrom, const To
} }
// check for matching function parameters // check for matching function parameters
if (returnMatch && argsMatch(tok->tokAt(2), functionToken->tokAt(2))) if (returnMatch && argsMatch(tok->tokAt(2), functionToken->tokAt(2), std::string(""), 0))
{ {
return true; return true;
} }

View File

@ -359,7 +359,11 @@ void Tokenizer::createTokens(std::istream &code)
{ {
if (lineNumbers.empty() || fileIndexes.empty()) if (lineNumbers.empty() || fileIndexes.empty())
{ {
<<<<<<< HEAD
cppcheckError(0); cppcheckError(0);
=======
std::cerr << "####### Preprocessor bug! #######\n";
>>>>>>> asd
deallocateTokens(); deallocateTokens();
return; return;
} }

View File

@ -733,6 +733,63 @@ private:
"[test.cpp:21]: (style) Member variable not initialized in the constructor 'B::b'\n" "[test.cpp:21]: (style) Member variable not initialized in the constructor 'B::b'\n"
"[test.cpp:22]: (style) Member variable not initialized in the constructor 'C::c'\n" "[test.cpp:22]: (style) Member variable not initialized in the constructor 'C::c'\n"
"[test.cpp:23]: (style) Member variable not initialized in the constructor 'D::d'\n", errout.str()); "[test.cpp:23]: (style) Member variable not initialized in the constructor 'D::d'\n", errout.str());
check("class A {\n"
"public:\n"
" A();\n"
" struct B {\n"
" B();\n"
" struct C {\n"
" C();\n"
" struct D {\n"
" D(const D &);\n"
" int d;\n"
" };\n"
" int c;\n"
" };\n"
" int b;\n"
" };\n"
"private:\n"
" int a;\n"
" B b;\n"
"};\n"
"A::A(){}\n"
"A::B::B(){}\n"
"A::B::C::C(){}\n"
"A::B::C::D::D(const A::B::C::D & d){}\n");
ASSERT_EQUALS("[test.cpp:20]: (style) Member variable not initialized in the constructor 'A::a'\n"
"[test.cpp:21]: (style) Member variable not initialized in the constructor 'B::b'\n"
"[test.cpp:22]: (style) Member variable not initialized in the constructor 'C::c'\n"
"[test.cpp:23]: (style) Member variable not initialized in the constructor 'D::d'\n", errout.str());
check("class A {\n"
"public:\n"
" A();\n"
" struct B {\n"
" B();\n"
" struct C {\n"
" C();\n"
" struct D {\n"
" struct E { };\n"
" E d;\n"
" D(const E &);\n"
" };\n"
" int c;\n"
" };\n"
" int b;\n"
" };\n"
"private:\n"
" int a;\n"
" B b;\n"
"};\n"
"A::A(){}\n"
"A::B::B(){}\n"
"A::B::C::C(){}\n"
"A::B::C::D::D(const A::B::C::D::E & e){}\n");
ASSERT_EQUALS("[test.cpp:21]: (style) Member variable not initialized in the constructor 'A::a'\n"
"[test.cpp:22]: (style) Member variable not initialized in the constructor 'B::b'\n"
"[test.cpp:23]: (style) Member variable not initialized in the constructor 'C::c'\n"
"[test.cpp:24]: (style) Member variable not initialized in the constructor 'D::d'\n", errout.str());
} }
void initvar_destructor() void initvar_destructor()