From 9462102245ca4461a0bd8bee574be76cb00b4dd3 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Tue, 22 Dec 2020 12:06:26 +0100 Subject: [PATCH] Add cache to hierarchy visitor, fix following typedefs and usings In case we already visited the same base class symbol in the same scope we already know the fully qualified name for base class, so no need to search it again. We store all visited symbols with their scopes in cache. This speeds up building type hierarchy, especially for large trees, like for creator project and showing type hierarchy for QObject: build time before this change was about 300 sec, now it's about 130 sec. Sometimes the old code didn't follow properly base classes that were typedefs to other classes (like in creator project: Debugger::Internal::RegisterHandler is derived from RegisterModel, and RegisterModel is a typedef to Utils::TreeModel). This caused that some subclasses were omitted form resulting type hierarchy. E.g. type hierarchy in creator project for QObject lacked about 8 subclasses. Change-Id: I03c5aef65b7d7cb0ed279d3558aebc8a55e856b4 Reviewed-by: hjk --- src/plugins/cpptools/typehierarchybuilder.cpp | 85 ++++++++++++------- src/plugins/cpptools/typehierarchybuilder.h | 3 +- 2 files changed, 57 insertions(+), 31 deletions(-) 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;