diff --git a/src/plugins/cpptools/typehierarchybuilder.cpp b/src/plugins/cpptools/typehierarchybuilder.cpp index cc58a8aad75..f975491d392 100644 --- a/src/plugins/cpptools/typehierarchybuilder.cpp +++ b/src/plugins/cpptools/typehierarchybuilder.cpp @@ -42,9 +42,10 @@ QString unqualifyName(const QString &qualifiedName) class DerivedHierarchyVisitor : public CPlusPlus::SymbolVisitor { public: - explicit DerivedHierarchyVisitor(const QString &qualifiedName) + explicit DerivedHierarchyVisitor(const QString &qualifiedName, QHash> &cache) : _qualifiedName(qualifiedName) , _unqualifiedName(unqualifyName(qualifiedName)) + , _cache(cache) {} void execute(const CPlusPlus::Document::Ptr &doc, const CPlusPlus::Snapshot &snapshot); @@ -55,11 +56,14 @@ public: const QSet otherBases() { return _otherBases; } private: + CPlusPlus::Symbol *lookup(const CPlusPlus::Name *symbolName, CPlusPlus::Scope *enclosingScope); + CPlusPlus::LookupContext _context; QString _qualifiedName; QString _unqualifiedName; CPlusPlus::Overview _overview; - QHash _actualBases; + // full scope name to base symbol name to fully qualified base symbol name + QHash> &_cache; QSet _otherBases; QList _derived; }; @@ -75,45 +79,64 @@ void DerivedHierarchyVisitor::execute(const CPlusPlus::Document::Ptr &doc, accept(doc->globalSymbolAt(i)); } +CPlusPlus::Symbol *DerivedHierarchyVisitor::lookup(const CPlusPlus::Name *symbolName, CPlusPlus::Scope *enclosingScope) +{ + QList items = _context.lookup(symbolName, enclosingScope); + + CPlusPlus::Symbol *actualBaseSymbol = nullptr; + + for (const CPlusPlus::LookupItem &item : items) { + CPlusPlus::Symbol *s = item.declaration(); + if (!s) + continue; + if (!s->isClass() && !s->isTemplate() && !s->isTypedef()) + continue; + actualBaseSymbol = s; + break; + } + + if (!actualBaseSymbol) + return nullptr; + + if (actualBaseSymbol->isTypedef()) { + CPlusPlus::NamedType *namedType = actualBaseSymbol->type()->asNamedType(); + if (!namedType) { + // Anonymous aggregate such as: typedef struct {} Empty; + return nullptr; + } + actualBaseSymbol = lookup(namedType->name(), actualBaseSymbol->enclosingScope()); + } + + return actualBaseSymbol; +} + bool DerivedHierarchyVisitor::visit(CPlusPlus::Class *symbol) { + const QList &fullScope + = CPlusPlus::LookupContext::fullyQualifiedName(symbol->enclosingScope()); + const QString fullScopeName = _overview.prettyName(fullScope); + for (int i = 0; i < symbol->baseClassCount(); ++i) { CPlusPlus::BaseClass *baseSymbol = symbol->baseClassAt(i); - QString baseName = _actualBases.value(baseSymbol); - if (baseName.isEmpty()) { - QList items = _context.lookup(baseSymbol->name(), symbol->enclosingScope()); - if (items.isEmpty() || !items.first().declaration()) + const QString &baseName = _overview.prettyName(baseSymbol->name()); + QString fullBaseName = _cache.value(fullScopeName).value(baseName); + if (fullBaseName.isEmpty()) { + CPlusPlus::Symbol *actualBaseSymbol = lookup(baseSymbol->name(), symbol->enclosingScope()); + if (!actualBaseSymbol) continue; - CPlusPlus::Symbol *actualBaseSymbol = items.first().declaration(); - if (actualBaseSymbol->isTypedef()) { - CPlusPlus::NamedType *namedType = actualBaseSymbol->type()->asNamedType(); - if (!namedType) { - // Anonymous aggregate such as: typedef struct {} Empty; - continue; - } - const QString &typeName = _overview.prettyName(namedType->name()); - if (typeName == _unqualifiedName || typeName == _qualifiedName) { - items = _context.lookup(namedType->name(), actualBaseSymbol->enclosingScope()); - if (items.isEmpty() || !items.first().declaration()) - continue; - actualBaseSymbol = items.first().declaration(); - } - } - const QList &full = CPlusPlus::LookupContext::fullyQualifiedName(actualBaseSymbol); - baseName = _overview.prettyName(full); - _actualBases.insert(baseSymbol, baseName); + fullBaseName = _overview.prettyName(full); + _cache[fullScopeName].insert(baseName, fullBaseName); } - if (_qualifiedName == baseName) + if (_qualifiedName == fullBaseName) _derived.append(symbol); else - _otherBases.insert(baseName); + _otherBases.insert(fullBaseName); } - return true; } @@ -147,7 +170,8 @@ TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy(QFutureInterfaceBa { TypeHierarchy hierarchy(symbol); TypeHierarchyBuilder builder; - builder.buildDerived(futureInterface, &hierarchy, snapshot); + QHash> cache; + builder.buildDerived(futureInterface, &hierarchy, snapshot, cache); return hierarchy; } @@ -164,6 +188,7 @@ static Utils::FilePaths filesDependingOn(const CPlusPlus::Snapshot &snapshot, void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface, TypeHierarchy *typeHierarchy, const CPlusPlus::Snapshot &snapshot, + QHash> &cache, int depth) { CPlusPlus::Symbol *symbol = typeHierarchy->_symbol; @@ -173,7 +198,7 @@ void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface, _visited.insert(symbol); const QString &symbolName = _overview.prettyName(CPlusPlus::LookupContext::fullyQualifiedName(symbol)); - DerivedHierarchyVisitor visitor(symbolName); + DerivedHierarchyVisitor visitor(symbolName, cache); const Utils::FilePaths &dependingFiles = filesDependingOn(snapshot, symbol); if (depth == 0) @@ -198,7 +223,7 @@ void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface, const QList &derived = visitor.derived(); for (CPlusPlus::Symbol *s : derived) { TypeHierarchy derivedHierarchy(s); - buildDerived(futureInterface, &derivedHierarchy, snapshot, depth + 1); + buildDerived(futureInterface, &derivedHierarchy, snapshot, cache, depth + 1); if (futureInterface.isCanceled()) return; typeHierarchy->_hierarchy.append(derivedHierarchy); diff --git a/src/plugins/cpptools/typehierarchybuilder.h b/src/plugins/cpptools/typehierarchybuilder.h index 7df1a210a11..0439b25c5b5 100644 --- a/src/plugins/cpptools/typehierarchybuilder.h +++ b/src/plugins/cpptools/typehierarchybuilder.h @@ -67,7 +67,8 @@ public: private: TypeHierarchyBuilder() = default; void buildDerived(QFutureInterfaceBase &futureInterface, TypeHierarchy *typeHierarchy, - const CPlusPlus::Snapshot &snapshot, int depth = 0); + const CPlusPlus::Snapshot &snapshot, + QHash > &cache, int depth = 0); QSet _visited; QHash > _candidates;