forked from qt-creator/qt-creator
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 <hjk@qt.io>
This commit is contained in:
@@ -42,9 +42,10 @@ QString unqualifyName(const QString &qualifiedName)
|
|||||||
class DerivedHierarchyVisitor : public CPlusPlus::SymbolVisitor
|
class DerivedHierarchyVisitor : public CPlusPlus::SymbolVisitor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit DerivedHierarchyVisitor(const QString &qualifiedName)
|
explicit DerivedHierarchyVisitor(const QString &qualifiedName, QHash<QString, QHash<QString, QString>> &cache)
|
||||||
: _qualifiedName(qualifiedName)
|
: _qualifiedName(qualifiedName)
|
||||||
, _unqualifiedName(unqualifyName(qualifiedName))
|
, _unqualifiedName(unqualifyName(qualifiedName))
|
||||||
|
, _cache(cache)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void execute(const CPlusPlus::Document::Ptr &doc, const CPlusPlus::Snapshot &snapshot);
|
void execute(const CPlusPlus::Document::Ptr &doc, const CPlusPlus::Snapshot &snapshot);
|
||||||
@@ -55,11 +56,14 @@ public:
|
|||||||
const QSet<QString> otherBases() { return _otherBases; }
|
const QSet<QString> otherBases() { return _otherBases; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
CPlusPlus::Symbol *lookup(const CPlusPlus::Name *symbolName, CPlusPlus::Scope *enclosingScope);
|
||||||
|
|
||||||
CPlusPlus::LookupContext _context;
|
CPlusPlus::LookupContext _context;
|
||||||
QString _qualifiedName;
|
QString _qualifiedName;
|
||||||
QString _unqualifiedName;
|
QString _unqualifiedName;
|
||||||
CPlusPlus::Overview _overview;
|
CPlusPlus::Overview _overview;
|
||||||
QHash<CPlusPlus::Symbol *, QString> _actualBases;
|
// full scope name to base symbol name to fully qualified base symbol name
|
||||||
|
QHash<QString, QHash<QString, QString>> &_cache;
|
||||||
QSet<QString> _otherBases;
|
QSet<QString> _otherBases;
|
||||||
QList<CPlusPlus::Symbol *> _derived;
|
QList<CPlusPlus::Symbol *> _derived;
|
||||||
};
|
};
|
||||||
@@ -75,45 +79,64 @@ void DerivedHierarchyVisitor::execute(const CPlusPlus::Document::Ptr &doc,
|
|||||||
accept(doc->globalSymbolAt(i));
|
accept(doc->globalSymbolAt(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CPlusPlus::Symbol *DerivedHierarchyVisitor::lookup(const CPlusPlus::Name *symbolName, CPlusPlus::Scope *enclosingScope)
|
||||||
|
{
|
||||||
|
QList<CPlusPlus::LookupItem> 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)
|
bool DerivedHierarchyVisitor::visit(CPlusPlus::Class *symbol)
|
||||||
{
|
{
|
||||||
|
const QList<const CPlusPlus::Name *> &fullScope
|
||||||
|
= CPlusPlus::LookupContext::fullyQualifiedName(symbol->enclosingScope());
|
||||||
|
const QString fullScopeName = _overview.prettyName(fullScope);
|
||||||
|
|
||||||
for (int i = 0; i < symbol->baseClassCount(); ++i) {
|
for (int i = 0; i < symbol->baseClassCount(); ++i) {
|
||||||
CPlusPlus::BaseClass *baseSymbol = symbol->baseClassAt(i);
|
CPlusPlus::BaseClass *baseSymbol = symbol->baseClassAt(i);
|
||||||
|
|
||||||
QString baseName = _actualBases.value(baseSymbol);
|
const QString &baseName = _overview.prettyName(baseSymbol->name());
|
||||||
if (baseName.isEmpty()) {
|
QString fullBaseName = _cache.value(fullScopeName).value(baseName);
|
||||||
QList<CPlusPlus::LookupItem> items = _context.lookup(baseSymbol->name(), symbol->enclosingScope());
|
if (fullBaseName.isEmpty()) {
|
||||||
if (items.isEmpty() || !items.first().declaration())
|
CPlusPlus::Symbol *actualBaseSymbol = lookup(baseSymbol->name(), symbol->enclosingScope());
|
||||||
|
if (!actualBaseSymbol)
|
||||||
continue;
|
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<const CPlusPlus::Name *> &full
|
const QList<const CPlusPlus::Name *> &full
|
||||||
= CPlusPlus::LookupContext::fullyQualifiedName(actualBaseSymbol);
|
= CPlusPlus::LookupContext::fullyQualifiedName(actualBaseSymbol);
|
||||||
baseName = _overview.prettyName(full);
|
fullBaseName = _overview.prettyName(full);
|
||||||
_actualBases.insert(baseSymbol, baseName);
|
_cache[fullScopeName].insert(baseName, fullBaseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_qualifiedName == baseName)
|
if (_qualifiedName == fullBaseName)
|
||||||
_derived.append(symbol);
|
_derived.append(symbol);
|
||||||
else
|
else
|
||||||
_otherBases.insert(baseName);
|
_otherBases.insert(fullBaseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,7 +170,8 @@ TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy(QFutureInterfaceBa
|
|||||||
{
|
{
|
||||||
TypeHierarchy hierarchy(symbol);
|
TypeHierarchy hierarchy(symbol);
|
||||||
TypeHierarchyBuilder builder;
|
TypeHierarchyBuilder builder;
|
||||||
builder.buildDerived(futureInterface, &hierarchy, snapshot);
|
QHash<QString, QHash<QString, QString>> cache;
|
||||||
|
builder.buildDerived(futureInterface, &hierarchy, snapshot, cache);
|
||||||
return hierarchy;
|
return hierarchy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,6 +188,7 @@ static Utils::FilePaths filesDependingOn(const CPlusPlus::Snapshot &snapshot,
|
|||||||
void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface,
|
void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface,
|
||||||
TypeHierarchy *typeHierarchy,
|
TypeHierarchy *typeHierarchy,
|
||||||
const CPlusPlus::Snapshot &snapshot,
|
const CPlusPlus::Snapshot &snapshot,
|
||||||
|
QHash<QString, QHash<QString, QString>> &cache,
|
||||||
int depth)
|
int depth)
|
||||||
{
|
{
|
||||||
CPlusPlus::Symbol *symbol = typeHierarchy->_symbol;
|
CPlusPlus::Symbol *symbol = typeHierarchy->_symbol;
|
||||||
@@ -173,7 +198,7 @@ void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface,
|
|||||||
_visited.insert(symbol);
|
_visited.insert(symbol);
|
||||||
|
|
||||||
const QString &symbolName = _overview.prettyName(CPlusPlus::LookupContext::fullyQualifiedName(symbol));
|
const QString &symbolName = _overview.prettyName(CPlusPlus::LookupContext::fullyQualifiedName(symbol));
|
||||||
DerivedHierarchyVisitor visitor(symbolName);
|
DerivedHierarchyVisitor visitor(symbolName, cache);
|
||||||
|
|
||||||
const Utils::FilePaths &dependingFiles = filesDependingOn(snapshot, symbol);
|
const Utils::FilePaths &dependingFiles = filesDependingOn(snapshot, symbol);
|
||||||
if (depth == 0)
|
if (depth == 0)
|
||||||
@@ -198,7 +223,7 @@ void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface,
|
|||||||
const QList<CPlusPlus::Symbol *> &derived = visitor.derived();
|
const QList<CPlusPlus::Symbol *> &derived = visitor.derived();
|
||||||
for (CPlusPlus::Symbol *s : derived) {
|
for (CPlusPlus::Symbol *s : derived) {
|
||||||
TypeHierarchy derivedHierarchy(s);
|
TypeHierarchy derivedHierarchy(s);
|
||||||
buildDerived(futureInterface, &derivedHierarchy, snapshot, depth + 1);
|
buildDerived(futureInterface, &derivedHierarchy, snapshot, cache, depth + 1);
|
||||||
if (futureInterface.isCanceled())
|
if (futureInterface.isCanceled())
|
||||||
return;
|
return;
|
||||||
typeHierarchy->_hierarchy.append(derivedHierarchy);
|
typeHierarchy->_hierarchy.append(derivedHierarchy);
|
||||||
|
|||||||
@@ -67,7 +67,8 @@ public:
|
|||||||
private:
|
private:
|
||||||
TypeHierarchyBuilder() = default;
|
TypeHierarchyBuilder() = default;
|
||||||
void buildDerived(QFutureInterfaceBase &futureInterface, TypeHierarchy *typeHierarchy,
|
void buildDerived(QFutureInterfaceBase &futureInterface, TypeHierarchy *typeHierarchy,
|
||||||
const CPlusPlus::Snapshot &snapshot, int depth = 0);
|
const CPlusPlus::Snapshot &snapshot,
|
||||||
|
QHash<QString, QHash<QString, QString> > &cache, int depth = 0);
|
||||||
|
|
||||||
QSet<CPlusPlus::Symbol *> _visited;
|
QSet<CPlusPlus::Symbol *> _visited;
|
||||||
QHash<Utils::FilePath, QSet<QString> > _candidates;
|
QHash<Utils::FilePath, QSet<QString> > _candidates;
|
||||||
|
|||||||
Reference in New Issue
Block a user