From 5423262bda744861db11339bcea0453399e7fc1f Mon Sep 17 00:00:00 2001 From: chrchr Date: Mon, 21 Aug 2023 11:35:35 +0200 Subject: [PATCH] Fix #11886 performance regression (hang) in 2.12dev --- lib/symboldatabase.cpp | 14 +++++++++++++- test/testclass.cpp | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index f64caa82e27..bb487db8336 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -4350,6 +4350,18 @@ const Function *Function::getOverriddenFunction(bool *foundAllBaseClasses) const return getOverriddenFunctionRecursive(nestedIn->definedType, foundAllBaseClasses); } +// prevent recursion if base is the same except for different template parameters +static bool isDerivedFromItself(const std::string& thisName, const std::string& baseName) +{ + const auto posThis = thisName.find('<'); + if (posThis == std::string::npos) + return false; + const auto posBase = baseName.find('<'); + if (posBase == std::string::npos) + return false; + return posThis == posBase && thisName.compare(0, posThis, baseName); +} + const Function * Function::getOverriddenFunctionRecursive(const ::Type* baseType, bool *foundAllBaseClasses) const { // check each base class @@ -4402,7 +4414,7 @@ const Function * Function::getOverriddenFunctionRecursive(const ::Type* baseType } } - if (!derivedFromType->derivedFrom.empty() && !derivedFromType->hasCircularDependencies()) { + if (!derivedFromType->derivedFrom.empty() && !derivedFromType->hasCircularDependencies() && !isDerivedFromItself(baseType->classScope->className, i.name)) { // avoid endless recursion, see #5289 Crash: Stack overflow in isImplicitlyVirtual_rec when checking SVN and // #5590 with a loop within the class hierarchy. const Function *func = getOverriddenFunctionRecursive(derivedFromType, foundAllBaseClasses); diff --git a/test/testclass.cpp b/test/testclass.cpp index b2a343a4446..5413a56c199 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -183,6 +183,7 @@ class TestClass : public TestFixture { TEST_CASE(const89); TEST_CASE(const90); TEST_CASE(const91); + TEST_CASE(const92); TEST_CASE(const_handleDefaultParameters); TEST_CASE(const_passThisToMemberOfOtherClass); @@ -6654,6 +6655,20 @@ class TestClass : public TestFixture { ASSERT_EQUALS("", errout.str()); } + void const92() { // #11886 + checkConst("void g(int);\n" + "template\n" + "struct S : public S {\n" + " void f() {\n" + " g(n - 1);\n" + " }\n" + "};\n" + "template<>\n" + "struct S<0> {};\n" + "struct D : S<150> {};\n"); + // don't hang + } + void const_handleDefaultParameters() { checkConst("struct Foo {\n" " void foo1(int i, int j = 0) {\n"