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();
if (!symbol)
continue;
if (!symbol->isClass() && !symbol->isTemplate() && !symbol->isForwardClassDeclaration())
if (!symbol->isClass() && !symbol->isTemplate() && !symbol->isForwardClassDeclaration() && !symbol->isTypedef())
continue;
lookupItem = item;
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;
}
break;
}

View File

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

View File

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