diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 1e01525db..1fbc22135 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -3056,7 +3056,9 @@ const Token *Type::initBaseInfo(const Token *tok, const Token *tok1) } } - base.type = classScope->check->findType(base.nameTok, classScope); + const Type * baseType = classScope->check->findType(base.nameTok, enclosingScope); + if (baseType && !baseType->findDependency(this)) + base.type = baseType; // save pattern for base class name derivedFrom.push_back(base); diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 0780fd65a..0e7131ae1 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1755,6 +1755,8 @@ namespace { fullName = name; ScopeInfo3 *scope = parent; while (scope && scope->parent) { + if (scope->name.empty()) + break; fullName = scope->name + " :: " + fullName; scope = scope->parent; } @@ -1770,14 +1772,14 @@ namespace { std::set recordTypes; std::set baseTypes; - ScopeInfo3 *addChild(Type type, const std::string &name, const Token *bodyStart, const Token *bodyEnd) { - children.emplace_back(this, type, name, bodyStart, bodyEnd); + ScopeInfo3 *addChild(Type scopeType, const std::string &scopeName, const Token *bodyStartToken, const Token *bodyEndToken) { + children.emplace_back(this, scopeType, scopeName, bodyStartToken, bodyEndToken); return &children.back(); } - bool hasChild(const std::string &name) const { + bool hasChild(const std::string &childName) const { for (const auto & child : children) { - if (child.name == name) + if (child.name == childName) return true; } return false; @@ -1824,24 +1826,39 @@ namespace { return nullptr; } + const ScopeInfo3 * findInChildren(const std::string & scope) const { + for (const auto & child : children) { + if (child.name == scope || child.fullName == scope) + return &child; + else { + const ScopeInfo3 * temp = child.findInChildren(scope); + if (temp) + return temp; + } + } + return nullptr; + } + const ScopeInfo3 * findScope(const std::string & scope) const { const ScopeInfo3 * tempScope = this; while (tempScope) { + // check children for (const auto & child : tempScope->children) { - if (child.type == Record && (child.name == scope || child.fullName == scope)) + if (&child != this && child.type == Record && (child.name == scope || child.fullName == scope)) return &child; } + // check siblings for same name + if (tempScope->parent) { + for (const auto &sibling : tempScope->parent->children) { + if (sibling.name == tempScope->name && &sibling != this) { + const ScopeInfo3 * temp = sibling.findInChildren(scope); + if (temp) + return temp; + } + } + } tempScope = tempScope->parent; } - // check for another scope with same name - const ScopeInfo3 * global = this; - while (global->parent) - global = global->parent; - for (const ScopeInfo3 & tempChild : global->children) { - const ScopeInfo3 * temp = tempChild.findScopeRecursive(scope); - if (temp) - return temp; - } return nullptr; } diff --git a/test/testclass.cpp b/test/testclass.cpp index 990fd82fb..29ea8a45f 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -5546,20 +5546,20 @@ private: } void const61() { // ticket #5606 - don't crash + // this code is invalid so a false negative is OK checkConst("class MixerParticipant : public MixerParticipant {\n" " int GetAudioFrame();\n" "};\n" "int MixerParticipant::GetAudioFrame() {\n" " return 0;\n" "}"); - ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:2]: (performance, inconclusive) Technically the member function 'MixerParticipant::GetAudioFrame' can be static (but you may consider moving to unnamed namespace).\n", errout.str()); + // this code is invalid so a false negative is OK checkConst("class MixerParticipant : public MixerParticipant {\n" " bool InitializeFileReader() {\n" " printf(\"music\");\n" " }\n" "};"); - ASSERT_EQUALS("[test.cpp:2]: (performance, inconclusive) Technically the member function 'MixerParticipant::InitializeFileReader' can be static (but you may consider moving to unnamed namespace).\n", errout.str()); // Based on an example from SVN source code causing an endless recursion within CheckClass::isConstMemberFunc() // A more complete example including a template declaration like diff --git a/test/testsimplifyusing.cpp b/test/testsimplifyusing.cpp index 0b3ec5275..0bac2a8ed 100644 --- a/test/testsimplifyusing.cpp +++ b/test/testsimplifyusing.cpp @@ -65,6 +65,7 @@ private: TEST_CASE(simplifyUsing16); TEST_CASE(simplifyUsing17); TEST_CASE(simplifyUsing18); + TEST_CASE(simplifyUsing19); TEST_CASE(simplifyUsing8970); TEST_CASE(simplifyUsing8971); @@ -463,6 +464,18 @@ private: tok(code, false); // don't crash } + void simplifyUsing19() { + const char code[] = "namespace a {\n" + "using b = int;\n" + "void foo::c() { }\n" + "void foo::d() { }\n" + "void foo::e() {\n" + " using b = float;\n" + "}\n" + "}"; + tok(code, false); // don't hang + } + void simplifyUsing8970() { const char code[] = "using V = std::vector;\n" "struct A {\n"