Show type hierarchy also for typedefs

Make it possible to show type hierarchy for
typedefs and unsings. Before, no type hierarchy
was shown.

Change-Id: I63ffa9c544072d66c42de8edf306c898d2fa90cb
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Jarek Kobus
2021-01-05 10:15:36 +01:00
parent 1e2e3f8e48
commit 661193f67b
3 changed files with 89 additions and 66 deletions

View File

@@ -471,9 +471,19 @@ QFuture<QSharedPointer<CppElement>> CppElementEvaluator::execute(SourceFunction
Symbol *symbol = item.declaration(); Symbol *symbol = item.declaration();
if (!symbol) if (!symbol)
continue; continue;
if (!symbol->isClass() && !symbol->isTemplate() && !symbol->isForwardClassDeclaration()) if (!symbol->isClass() && !symbol->isTemplate() && !symbol->isForwardClassDeclaration() && !symbol->isTypedef())
continue; continue;
if (symbol->isTypedef()) {
CPlusPlus::NamedType *namedType = symbol->type()->asNamedType();
if (!namedType) {
// Anonymous aggregate such as: typedef struct {} Empty;
continue;
}
lookupItem = TypeHierarchyBuilder::followTypedef(typeOfExpression.context(),
namedType->name(), symbol->enclosingScope());
} else {
lookupItem = item; lookupItem = item;
}
break; break;
} }

View File

@@ -27,6 +27,7 @@
#include <cplusplus/FindUsages.h> #include <cplusplus/FindUsages.h>
using namespace CPlusPlus;
using namespace CppTools; using namespace CppTools;
namespace { namespace {
@@ -39,7 +40,7 @@ QString unqualifyName(const QString &qualifiedName)
return qualifiedName.right(qualifiedName.length() - index - 2); return qualifiedName.right(qualifiedName.length() - index - 2);
} }
class DerivedHierarchyVisitor : public CPlusPlus::SymbolVisitor class DerivedHierarchyVisitor : public SymbolVisitor
{ {
public: public:
explicit DerivedHierarchyVisitor(const QString &qualifiedName, QHash<QString, QHash<QString, QString>> &cache) explicit DerivedHierarchyVisitor(const QString &qualifiedName, QHash<QString, QHash<QString, QString>> &cache)
@@ -48,86 +49,56 @@ public:
, _cache(cache) , _cache(cache)
{} {}
void execute(const CPlusPlus::Document::Ptr &doc, const CPlusPlus::Snapshot &snapshot); void execute(const Document::Ptr &doc, const Snapshot &snapshot);
bool visit(CPlusPlus::Class *) override; bool visit(Class *) override;
const QList<CPlusPlus::Symbol *> &derived() { return _derived; } const QList<Symbol *> &derived() { return _derived; }
const QSet<QString> otherBases() { return _otherBases; } const QSet<QString> otherBases() { return _otherBases; }
private: private:
CPlusPlus::Symbol *lookup(const CPlusPlus::Name *symbolName, CPlusPlus::Scope *enclosingScope); Symbol *lookup(const Name *symbolName, Scope *enclosingScope);
CPlusPlus::LookupContext _context; LookupContext _context;
QString _qualifiedName; QString _qualifiedName;
QString _unqualifiedName; QString _unqualifiedName;
CPlusPlus::Overview _overview; Overview _overview;
// full scope name to base symbol name to fully qualified base symbol name // full scope name to base symbol name to fully qualified base symbol name
QHash<QString, QHash<QString, QString>> &_cache; QHash<QString, QHash<QString, QString>> &_cache;
QSet<QString> _otherBases; QSet<QString> _otherBases;
QList<CPlusPlus::Symbol *> _derived; QList<Symbol *> _derived;
}; };
void DerivedHierarchyVisitor::execute(const CPlusPlus::Document::Ptr &doc, void DerivedHierarchyVisitor::execute(const Document::Ptr &doc,
const CPlusPlus::Snapshot &snapshot) const Snapshot &snapshot)
{ {
_derived.clear(); _derived.clear();
_otherBases.clear(); _otherBases.clear();
_context = CPlusPlus::LookupContext(doc, snapshot); _context = LookupContext(doc, snapshot);
for (int i = 0; i < doc->globalSymbolCount(); ++i) for (int i = 0; i < doc->globalSymbolCount(); ++i)
accept(doc->globalSymbolAt(i)); accept(doc->globalSymbolAt(i));
} }
CPlusPlus::Symbol *DerivedHierarchyVisitor::lookup(const CPlusPlus::Name *symbolName, CPlusPlus::Scope *enclosingScope) bool DerivedHierarchyVisitor::visit(Class *symbol)
{ {
QList<CPlusPlus::LookupItem> items = _context.lookup(symbolName, enclosingScope); const QList<const Name *> &fullScope
= LookupContext::fullyQualifiedName(symbol->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<const CPlusPlus::Name *> &fullScope
= CPlusPlus::LookupContext::fullyQualifiedName(symbol->enclosingScope());
const QString fullScopeName = _overview.prettyName(fullScope); 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); BaseClass *baseSymbol = symbol->baseClassAt(i);
const QString &baseName = _overview.prettyName(baseSymbol->name()); const QString &baseName = _overview.prettyName(baseSymbol->name());
QString fullBaseName = _cache.value(fullScopeName).value(baseName); QString fullBaseName = _cache.value(fullScopeName).value(baseName);
if (fullBaseName.isEmpty()) { if (fullBaseName.isEmpty()) {
CPlusPlus::Symbol *actualBaseSymbol = lookup(baseSymbol->name(), symbol->enclosingScope()); Symbol *actualBaseSymbol = TypeHierarchyBuilder::followTypedef(_context,
baseSymbol->name(), symbol->enclosingScope()).declaration();
if (!actualBaseSymbol) if (!actualBaseSymbol)
continue; continue;
const QList<const CPlusPlus::Name *> &full const QList<const Name *> &full
= CPlusPlus::LookupContext::fullyQualifiedName(actualBaseSymbol); = LookupContext::fullyQualifiedName(actualBaseSymbol);
fullBaseName = _overview.prettyName(full); fullBaseName = _overview.prettyName(full);
_cache[fullScopeName].insert(baseName, fullBaseName); _cache[fullScopeName].insert(baseName, fullBaseName);
} }
@@ -144,10 +115,10 @@ bool DerivedHierarchyVisitor::visit(CPlusPlus::Class *symbol)
TypeHierarchy::TypeHierarchy() = default; TypeHierarchy::TypeHierarchy() = default;
TypeHierarchy::TypeHierarchy(CPlusPlus::Symbol *symbol) : _symbol(symbol) TypeHierarchy::TypeHierarchy(Symbol *symbol) : _symbol(symbol)
{} {}
CPlusPlus::Symbol *TypeHierarchy::symbol() const Symbol *TypeHierarchy::symbol() const
{ {
return _symbol; return _symbol;
} }
@@ -157,16 +128,16 @@ const QList<TypeHierarchy> &TypeHierarchy::hierarchy() const
return _hierarchy; return _hierarchy;
} }
TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy(CPlusPlus::Symbol *symbol, TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy(Symbol *symbol,
const CPlusPlus::Snapshot &snapshot) const Snapshot &snapshot)
{ {
QFutureInterfaceBase dummy; QFutureInterfaceBase dummy;
return TypeHierarchyBuilder::buildDerivedTypeHierarchy(dummy, symbol, snapshot); return TypeHierarchyBuilder::buildDerivedTypeHierarchy(dummy, symbol, snapshot);
} }
TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy(QFutureInterfaceBase &futureInterface, TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy(QFutureInterfaceBase &futureInterface,
CPlusPlus::Symbol *symbol, Symbol *symbol,
const CPlusPlus::Snapshot &snapshot) const Snapshot &snapshot)
{ {
TypeHierarchy hierarchy(symbol); TypeHierarchy hierarchy(symbol);
TypeHierarchyBuilder builder; TypeHierarchyBuilder builder;
@@ -175,8 +146,41 @@ TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy(QFutureInterfaceBa
return hierarchy; return hierarchy;
} }
static Utils::FilePaths filesDependingOn(const CPlusPlus::Snapshot &snapshot, LookupItem TypeHierarchyBuilder::followTypedef(const LookupContext &context, const Name *symbolName, Scope *enclosingScope)
CPlusPlus::Symbol *symbol) {
QList<LookupItem> items = context.lookup(symbolName, enclosingScope);
Symbol *actualBaseSymbol = nullptr;
LookupItem matchingItem;
for (const LookupItem &item : items) {
Symbol *s = item.declaration();
if (!s)
continue;
if (!s->isClass() && !s->isTemplate() && !s->isTypedef())
continue;
actualBaseSymbol = s;
matchingItem = item;
break;
}
if (!actualBaseSymbol)
return LookupItem();
if (actualBaseSymbol->isTypedef()) {
NamedType *namedType = actualBaseSymbol->type()->asNamedType();
if (!namedType) {
// Anonymous aggregate such as: typedef struct {} Empty;
return LookupItem();
}
return followTypedef(context, namedType->name(), actualBaseSymbol->enclosingScope());
}
return matchingItem;
}
static Utils::FilePaths filesDependingOn(const Snapshot &snapshot,
Symbol *symbol)
{ {
if (!symbol) if (!symbol)
return Utils::FilePaths(); return Utils::FilePaths();
@@ -187,17 +191,17 @@ 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 Snapshot &snapshot,
QHash<QString, QHash<QString, QString>> &cache, QHash<QString, QHash<QString, QString>> &cache,
int depth) int depth)
{ {
CPlusPlus::Symbol *symbol = typeHierarchy->_symbol; Symbol *symbol = typeHierarchy->_symbol;
if (_visited.contains(symbol)) if (_visited.contains(symbol))
return; return;
_visited.insert(symbol); _visited.insert(symbol);
const QString &symbolName = _overview.prettyName(CPlusPlus::LookupContext::fullyQualifiedName(symbol)); const QString &symbolName = _overview.prettyName(LookupContext::fullyQualifiedName(symbol));
DerivedHierarchyVisitor visitor(symbolName, cache); DerivedHierarchyVisitor visitor(symbolName, cache);
const Utils::FilePaths &dependingFiles = filesDependingOn(snapshot, symbol); const Utils::FilePaths &dependingFiles = filesDependingOn(snapshot, symbol);
@@ -210,7 +214,7 @@ void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface,
return; return;
if (depth == 0) if (depth == 0)
futureInterface.setProgressValue(++i); futureInterface.setProgressValue(++i);
CPlusPlus::Document::Ptr doc = snapshot.document(fileName); Document::Ptr doc = snapshot.document(fileName);
if ((_candidates.contains(fileName) && !_candidates.value(fileName).contains(symbolName)) if ((_candidates.contains(fileName) && !_candidates.value(fileName).contains(symbolName))
|| !doc->control()->findIdentifier(symbol->identifier()->chars(), || !doc->control()->findIdentifier(symbol->identifier()->chars(),
symbol->identifier()->size())) { symbol->identifier()->size())) {
@@ -220,8 +224,8 @@ void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface,
visitor.execute(doc, snapshot); visitor.execute(doc, snapshot);
_candidates.insert(fileName, visitor.otherBases()); _candidates.insert(fileName, visitor.otherBases());
const QList<CPlusPlus::Symbol *> &derived = visitor.derived(); const QList<Symbol *> &derived = visitor.derived();
for (CPlusPlus::Symbol *s : derived) { for (Symbol *s : derived) {
TypeHierarchy derivedHierarchy(s); TypeHierarchy derivedHierarchy(s);
buildDerived(futureInterface, &derivedHierarchy, snapshot, cache, depth + 1); buildDerived(futureInterface, &derivedHierarchy, snapshot, cache, depth + 1);
if (futureInterface.isCanceled()) if (futureInterface.isCanceled())

View File

@@ -34,6 +34,13 @@
#include <QList> #include <QList>
#include <QSet> #include <QSet>
namespace CPlusPlus {
class LookupContext;
class LookupItem;
class Name;
class Scope;
}
namespace CppTools { namespace CppTools {
class CPPTOOLS_EXPORT TypeHierarchy class CPPTOOLS_EXPORT TypeHierarchy
@@ -63,7 +70,9 @@ public:
static TypeHierarchy buildDerivedTypeHierarchy(QFutureInterfaceBase &futureInterface, static TypeHierarchy buildDerivedTypeHierarchy(QFutureInterfaceBase &futureInterface,
CPlusPlus::Symbol *symbol, CPlusPlus::Symbol *symbol,
const CPlusPlus::Snapshot &snapshot); const CPlusPlus::Snapshot &snapshot);
static CPlusPlus::LookupItem followTypedef(const CPlusPlus::LookupContext &context,
const CPlusPlus::Name *symbolName,
CPlusPlus::Scope *enclosingScope);
private: private:
TypeHierarchyBuilder() = default; TypeHierarchyBuilder() = default;
void buildDerived(QFutureInterfaceBase &futureInterface, TypeHierarchy *typeHierarchy, void buildDerived(QFutureInterfaceBase &futureInterface, TypeHierarchy *typeHierarchy,