In case of a loop within the class hierarchie Function::isImplicitlyVirtual_rec() was entering an endless loop. Tracking the previously analyzed types shall prevent this.
This commit is contained in:
parent
1df5ccf315
commit
37befc75ef
|
@ -2029,7 +2029,7 @@ bool Function::isImplicitlyVirtual(bool defaultVal) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Function::isImplicitlyVirtual_rec(const ::Type* baseType, bool& safe) const
|
bool Function::isImplicitlyVirtual_rec(const ::Type* baseType, bool& safe, std::deque< const ::Type* > *anchestors) const
|
||||||
{
|
{
|
||||||
// check each base class
|
// check each base class
|
||||||
for (std::size_t i = 0; i < baseType->derivedFrom.size(); ++i) {
|
for (std::size_t i = 0; i < baseType->derivedFrom.size(); ++i) {
|
||||||
|
@ -2065,9 +2065,19 @@ bool Function::isImplicitlyVirtual_rec(const ::Type* baseType, bool& safe) const
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!baseType->derivedFrom[i].type->derivedFrom.empty()) {
|
if (!baseType->derivedFrom[i].type->derivedFrom.empty()) {
|
||||||
// avoid endless recursion, see #5289 Crash: Stack overflow in isImplicitlyVirtual_rec when checking SVN
|
// avoid endless recursion, see #5289 Crash: Stack overflow in isImplicitlyVirtual_rec when checking SVN and
|
||||||
if ((baseType != baseType->derivedFrom[i].type) && isImplicitlyVirtual_rec(baseType->derivedFrom[i].type, safe))
|
// #5590 with a loop within the class hierarchie.
|
||||||
return true;
|
// We do so by tracking all previously checked types in a deque.
|
||||||
|
std::deque< const ::Type* > local_anchestors;
|
||||||
|
if (!anchestors) {
|
||||||
|
anchestors=&local_anchestors;
|
||||||
|
}
|
||||||
|
anchestors->push_back(baseType);
|
||||||
|
if (std::find(anchestors->begin(), anchestors->end(), baseType->derivedFrom[i].type)==anchestors->end()) {
|
||||||
|
if (isImplicitlyVirtual_rec(baseType->derivedFrom[i].type, safe, anchestors)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// unable to find base class so assume it has no virtual function
|
// unable to find base class so assume it has no virtual function
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <deque>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
@ -603,7 +604,7 @@ public:
|
||||||
static bool argsMatch(const Scope *info, const Token *first, const Token *second, const std::string &path, unsigned int depth);
|
static bool argsMatch(const Scope *info, const Token *first, const Token *second, const std::string &path, unsigned int depth);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isImplicitlyVirtual_rec(const ::Type* type, bool& safe) const;
|
bool isImplicitlyVirtual_rec(const ::Type* type, bool& safe, std::deque<const ::Type* > *anchestors = nullptr) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CPPCHECKLIB Scope {
|
class CPPCHECKLIB Scope {
|
||||||
|
|
|
@ -1818,6 +1818,27 @@ private:
|
||||||
" }\n"
|
" }\n"
|
||||||
"};");
|
"};");
|
||||||
ASSERT(db && db->findScopeByName("Bar") && !db->findScopeByName("Bar")->functionList.front().isImplicitlyVirtual(false));
|
ASSERT(db && db->findScopeByName("Bar") && !db->findScopeByName("Bar")->functionList.front().isImplicitlyVirtual(false));
|
||||||
|
ASSERT_EQUALS(1, db->findScopeByName("Bar")->functionList.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// #5590
|
||||||
|
{
|
||||||
|
GET_SYMBOL_DB("class InfiniteB : InfiniteA {\n"
|
||||||
|
" class D {\n"
|
||||||
|
" };\n"
|
||||||
|
"};\n"
|
||||||
|
"namespace N {\n"
|
||||||
|
" class InfiniteA : InfiniteB {\n"
|
||||||
|
" };\n"
|
||||||
|
"}\n"
|
||||||
|
"class InfiniteA : InfiniteB {\n"
|
||||||
|
" void foo();\n"
|
||||||
|
"};\n"
|
||||||
|
"void InfiniteA::foo() {\n"
|
||||||
|
" C a;\n"
|
||||||
|
"}");
|
||||||
|
//ASSERT(db && db->findScopeByName("InfiniteA") && !db->findScopeByName("InfiniteA")->functionList.front().isImplicitlyVirtual());
|
||||||
|
TODO_ASSERT_EQUALS(1, 0, db->findScopeByName("InfiniteA")->functionList.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,6 +72,7 @@ private:
|
||||||
|
|
||||||
TEST_CASE(multiFile);
|
TEST_CASE(multiFile);
|
||||||
TEST_CASE(unknownBaseTemplate); // ticket #2580
|
TEST_CASE(unknownBaseTemplate); // ticket #2580
|
||||||
|
TEST_CASE(hierarchie_loop); // ticket 5590
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -692,6 +693,25 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hierarchie_loop() {
|
||||||
|
check("class InfiniteB : InfiniteA {\n"
|
||||||
|
" class D {\n"
|
||||||
|
" };\n"
|
||||||
|
"};\n"
|
||||||
|
"namespace N {\n"
|
||||||
|
" class InfiniteA : InfiniteB {\n"
|
||||||
|
" };\n"
|
||||||
|
"}\n"
|
||||||
|
"class InfiniteA : InfiniteB {\n"
|
||||||
|
" void foo();\n"
|
||||||
|
"};\n"
|
||||||
|
"void InfiniteA::foo() {\n"
|
||||||
|
" C a;\n"
|
||||||
|
"}");
|
||||||
|
|
||||||
|
ASSERT_EQUALS("[test.cpp:10]: (style) Unused private function: 'InfiniteA::foo'\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestUnusedPrivateFunction)
|
REGISTER_TEST(TestUnusedPrivateFunction)
|
||||||
|
|
Loading…
Reference in New Issue