Fix ticket #531 (false positive about missing virtual destructor)

http://sourceforge.net/apps/trac/cppcheck/ticket/531
This commit is contained in:
Reijo Tomperi 2009-08-04 22:23:22 +03:00
parent a34d6fd2de
commit 975e7778ab
2 changed files with 107 additions and 1 deletions

View File

@ -720,17 +720,28 @@ void CheckClass::virtualDestructor()
if (! base)
{
// Is the class declaration available?
base = Token::findmatch(_tokenizer->tokens(), (std::string("class ") + baseName[0] + " :|{").c_str());
base = Token::findmatch(_tokenizer->tokens(), (std::string("class ") + baseName[0] + " {").c_str());
if (base)
{
virtualDestructorError(base, baseName[0], derivedClass->str());
}
continue;
}
// There is a destructor. Check that it's virtual..
else if (base->str() == "virtual")
continue;
// TODO: This is just a temporary fix, better solution is needed.
// Skip situations where base class has base classes of its own, because
// some of the base classes might have virtual destructor.
// Proper solution is to check all of the base classes. If base class is not
// found or if one of the base classes has virtual destructor, error should not
// be printed. See TODO test case "virtualDestructorInherited"
if (!Token::findmatch(_tokenizer->tokens(), (std::string("class ") + baseName[0] + " {").c_str()))
continue;
// Make sure that the destructor is public (protected or private
// would not compile if inheritance is used in a way that would
// cause the bug we are trying to find here.)

View File

@ -41,6 +41,7 @@ private:
TEST_CASE(virtualDestructor4); // Derived class doesn't have a destructor => no error
TEST_CASE(virtualDestructor5); // Derived class has empty destructor => no error
TEST_CASE(virtualDestructorProtected);
TEST_CASE(virtualDestructorInherited);
TEST_CASE(uninitVar1);
TEST_CASE(uninitVarEnum);
@ -157,6 +158,100 @@ private:
ASSERT_EQUALS("", errout.str());
}
void virtualDestructorInherited()
{
// class A inherits virtual destructor from class Base -> no error
checkVirtualDestructor("class Base\n"
"{\n"
"public:\n"
"virtual ~Base() {}\n"
"};\n"
"class A : private Base\n"
"{\n"
"public:\n"
" ~A() { }\n"
"};\n"
"\n"
"class B : public A\n"
"{\n"
"public:\n"
" ~B() { int a; }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
// class A inherits virtual destructor from struct Base -> no error
// also notice that public is not given, but destructor is public, because
// we are using struct instead of class
checkVirtualDestructor("struct Base\n"
"{\n"
"virtual ~Base() {}\n"
"};\n"
"class A : public Base\n"
"{\n"
"};\n"
"\n"
"class B : public A\n"
"{\n"
"public:\n"
" ~B() { int a; }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
// Unknown Base class -> it could have virtual destructor, so ignore
checkVirtualDestructor("class A : private Base\n"
"{\n"
"public:\n"
" ~A() { }\n"
"};\n"
"\n"
"class B : public A\n"
"{\n"
"public:\n"
" ~B() { int a; }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
// Virtual destructor is inherited -> no error
checkVirtualDestructor("class Base2\n"
"{\n"
"virtual ~Base2() {}\n"
"};\n"
"class Base : public Base2\n"
"{\n"
"};\n"
"class A : private Base\n"
"{\n"
"public:\n"
" ~A() { }\n"
"};\n"
"\n"
"class B : public A\n"
"{\n"
"public:\n"
" ~B() { int a; }\n"
"};\n");
ASSERT_EQUALS("", errout.str());
// class A doesn't inherit virtual destructor from class Base -> error
checkVirtualDestructor("class Base\n"
"{\n"
"public:\n"
"~Base() {}\n"
"};\n"
"class A : private Base\n"
"{\n"
"public:\n"
" ~A() { }\n"
"};\n"
"\n"
"class B : public A\n"
"{\n"
"public:\n"
" ~B() { int a; }\n"
"};\n");
TODO_ASSERT_EQUALS("[test.cpp:7]: (error) Class A which is inherited by class B does not have a virtual destructor\n", errout.str());
}
void checkUninitVar(const char code[])
{
// Tokenize..