Modernize Type Hierarchy

Don't freeze UI on request for show Type Hierarchy.
Move the lookup code into a separate thread.
Don't clear tree hierarchy when waiting for new one.
Show progress indicator on top of old hierarchy instead.
Add a task to ProgressManager when working on a new hierarchy.
Handle canceling the process of showing Type Hierarchy.
Implement simple progress reporting for this process.
Optimize a bit DerivedHierarchyVisitor.

Change-Id: I3894ac6ed3f4834831831f083f718f8385ca346f
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Jarek Kobus
2020-11-30 17:02:33 +01:00
parent f2dd45d8ce
commit c400923308
6 changed files with 272 additions and 105 deletions

View File

@@ -32,11 +32,13 @@
#include <coreplugin/find/itemviewfind.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <cpptools/cppelementevaluator.h>
#include <utils/algorithm.h>
#include <utils/delegates.h>
#include <utils/navigationtreeview.h>
#include <utils/dropsupport.h>
#include <utils/navigationtreeview.h>
#include <utils/progressindicator.h>
#include <QApplication>
#include <QLabel>
@@ -107,10 +109,10 @@ CppTypeHierarchyWidget::CppTypeHierarchyWidget()
m_treeView->setDefaultDropAction(Qt::MoveAction);
connect(m_treeView, &QTreeView::activated, this, &CppTypeHierarchyWidget::onItemActivated);
m_noTypeHierarchyAvailableLabel = new QLabel(tr("No type hierarchy available"), this);
m_noTypeHierarchyAvailableLabel->setAlignment(Qt::AlignCenter);
m_noTypeHierarchyAvailableLabel->setAutoFillBackground(true);
m_noTypeHierarchyAvailableLabel->setBackgroundRole(QPalette::Base);
m_infoLabel = new QLabel(this);
m_infoLabel->setAlignment(Qt::AlignCenter);
m_infoLabel->setAutoFillBackground(true);
m_infoLabel->setBackgroundRole(QPalette::Base);
m_hierarchyWidget = new QWidget(this);
auto layout = new QVBoxLayout;
@@ -122,50 +124,83 @@ CppTypeHierarchyWidget::CppTypeHierarchyWidget()
m_stackLayout = new QStackedLayout;
m_stackLayout->addWidget(m_hierarchyWidget);
m_stackLayout->addWidget(m_noTypeHierarchyAvailableLabel);
m_stackLayout->setCurrentWidget(m_noTypeHierarchyAvailableLabel);
m_stackLayout->addWidget(m_infoLabel);
showNoTypeHierarchyLabel();
setLayout(m_stackLayout);
connect(CppEditorPlugin::instance(), &CppEditorPlugin::typeHierarchyRequested, this, &CppTypeHierarchyWidget::perform);
connect(CppEditorPlugin::instance(), &CppEditorPlugin::typeHierarchyRequested,
this, &CppTypeHierarchyWidget::perform);
connect(&m_futureWatcher, &QFutureWatcher<QSharedPointer<CppElement>>::finished,
this, &CppTypeHierarchyWidget::displayHierarchy);
}
CppTypeHierarchyWidget::~CppTypeHierarchyWidget() = default;
CppTypeHierarchyWidget::~CppTypeHierarchyWidget()
{
if (m_future.isRunning()) {
m_future.cancel();
m_future.waitForFinished();
}
}
void CppTypeHierarchyWidget::perform()
{
showNoTypeHierarchyLabel();
if (m_future.isRunning())
m_future.cancel();
auto editor = qobject_cast<CppEditor *>(Core::EditorManager::currentEditor());
if (!editor)
if (!editor) {
showNoTypeHierarchyLabel();
return;
}
auto widget = qobject_cast<CppEditorWidget *>(editor->widget());
if (!widget)
if (!widget) {
showNoTypeHierarchyLabel();
return;
}
clearTypeHierarchy();
showProgress();
CppElementEvaluator evaluator(widget);
evaluator.setLookupBaseClasses(true);
evaluator.setLookupDerivedClasses(true);
evaluator.execute();
if (evaluator.identifiedCppElement()) {
const QSharedPointer<CppElement> &cppElement = evaluator.cppElement();
CppElement *element = cppElement.data();
if (CppClass *cppClass = element->toCppClass()) {
m_inspectedClass->setText(cppClass->name);
m_inspectedClass->setLink(cppClass->link);
QStandardItem *bases = new QStandardItem(tr("Bases"));
m_model->invisibleRootItem()->appendRow(bases);
buildHierarchy(*cppClass, bases, true, &CppClass::bases);
QStandardItem *derived = new QStandardItem(tr("Derived"));
m_model->invisibleRootItem()->appendRow(derived);
buildHierarchy(*cppClass, derived, true, &CppClass::derived);
m_treeView->expandAll();
m_future = evaluator.asyncExecute();
m_futureWatcher.setFuture(m_future);
showTypeHierarchy();
}
Core::ProgressManager::addTask(m_future, tr("Evaluating Type Hierarchy"), "TypeHierarchy");
}
void CppTypeHierarchyWidget::displayHierarchy()
{
hideProgress();
clearTypeHierarchy();
if (!m_future.resultCount() || m_future.isCanceled()) {
showNoTypeHierarchyLabel();
return;
}
const QSharedPointer<CppElement> &cppElement = m_future.result();
if (cppElement.isNull()) {
showNoTypeHierarchyLabel();
return;
}
CppClass *cppClass = cppElement->toCppClass();
if (!cppClass) {
showNoTypeHierarchyLabel();
return;
}
m_inspectedClass->setText(cppClass->name);
m_inspectedClass->setLink(cppClass->link);
QStandardItem *bases = new QStandardItem(tr("Bases"));
m_model->invisibleRootItem()->appendRow(bases);
buildHierarchy(*cppClass, bases, true, &CppClass::bases);
QStandardItem *derived = new QStandardItem(tr("Derived"));
m_model->invisibleRootItem()->appendRow(derived);
buildHierarchy(*cppClass, derived, true, &CppClass::derived);
m_treeView->expandAll();
showTypeHierarchy();
}
void CppTypeHierarchyWidget::buildHierarchy(const CppClass &cppClass, QStandardItem *parent,
@@ -182,7 +217,8 @@ void CppTypeHierarchyWidget::buildHierarchy(const CppClass &cppClass, QStandardI
void CppTypeHierarchyWidget::showNoTypeHierarchyLabel()
{
m_stackLayout->setCurrentWidget(m_noTypeHierarchyAvailableLabel);
m_infoLabel->setText(tr("No type hierarchy available"));
m_stackLayout->setCurrentWidget(m_infoLabel);
}
void CppTypeHierarchyWidget::showTypeHierarchy()
@@ -190,6 +226,22 @@ void CppTypeHierarchyWidget::showTypeHierarchy()
m_stackLayout->setCurrentWidget(m_hierarchyWidget);
}
void CppTypeHierarchyWidget::showProgress()
{
m_infoLabel->setText(tr("Evaluating type hierarchy..."));
if (!m_progressIndicator) {
m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Large);
m_progressIndicator->attachToWidget(this);
}
m_progressIndicator->show();
m_progressIndicator->raise();
}
void CppTypeHierarchyWidget::hideProgress()
{
if (m_progressIndicator)
m_progressIndicator->hide();
}
void CppTypeHierarchyWidget::clearTypeHierarchy()
{
m_inspectedClass->clear();

View File

@@ -27,11 +27,14 @@
#include <coreplugin/inavigationwidgetfactory.h>
#include <QFuture>
#include <QFutureWatcher>
#include <QList>
#include <QString>
#include <QWidget>
#include <QSharedPointer>
#include <QStackedWidget>
#include <QStandardItemModel>
#include <QString>
#include <QWidget>
QT_BEGIN_NAMESPACE
class QLabel;
@@ -43,11 +46,12 @@ QT_END_NAMESPACE
namespace TextEditor { class TextEditorLinkLabel; }
namespace Utils {
class NavigationTreeView;
class AnnotatedItemDelegate;
class NavigationTreeView;
class ProgressIndicator;
}
namespace CppTools { class CppClass; }
namespace CppTools { class CppClass; class CppElement; }
namespace CppEditor {
namespace Internal {
@@ -75,12 +79,17 @@ public:
void perform();
private slots:
void displayHierarchy();
private:
typedef QList<CppTools::CppClass> CppTools::CppClass::*HierarchyMember;
void buildHierarchy(const CppTools::CppClass &cppClass, QStandardItem *parent,
bool isRoot, HierarchyMember member);
void showNoTypeHierarchyLabel();
void showTypeHierarchy();
void showProgress();
void hideProgress();
void clearTypeHierarchy();
void onItemActivated(const QModelIndex &index);
@@ -91,7 +100,10 @@ private:
QStandardItemModel *m_model = nullptr;
Utils::AnnotatedItemDelegate *m_delegate = nullptr;
TextEditor::TextEditorLinkLabel *m_inspectedClass = nullptr;
QLabel *m_noTypeHierarchyAvailableLabel = nullptr;
QLabel *m_infoLabel = nullptr;
QFuture<QSharedPointer<CppTools::CppElement>> m_future;
QFutureWatcher<QSharedPointer<CppTools::CppElement>> m_futureWatcher;
Utils::ProgressIndicator *m_progressIndicator = nullptr;
};
class CppTypeHierarchyFactory : public Core::INavigationWidgetFactory

View File

@@ -36,6 +36,8 @@
#include <cplusplus/Icons.h>
#include <cplusplus/TypeOfExpression.h>
#include <utils/runextensions.h>
#include <QDir>
#include <QSet>
#include <QQueue>
@@ -44,6 +46,14 @@ using namespace CPlusPlus;
namespace CppTools {
static void handleLookupItemMatch(QFutureInterface<QSharedPointer<CppElement>> &futureInterface,
const Snapshot &snapshot,
const LookupItem &lookupItem,
const LookupContext &context,
CppTools::SymbolFinder symbolFinder,
bool lookupBaseClasses,
bool lookupDerivedClasses);
static QStringList stripName(const QString &name)
{
QStringList all;
@@ -164,7 +174,8 @@ CppClass *CppClass::toCppClass()
return this;
}
void CppClass::lookupBases(Symbol *declaration, const LookupContext &context)
void CppClass::lookupBases(QFutureInterfaceBase &futureInterface,
Symbol *declaration, const LookupContext &context)
{
using Data = QPair<ClassOrNamespace*, CppClass*>;
@@ -174,6 +185,8 @@ void CppClass::lookupBases(Symbol *declaration, const LookupContext &context)
QQueue<Data> q;
q.enqueue(qMakePair(clazz, this));
while (!q.isEmpty()) {
if (futureInterface.isCanceled())
return;
Data current = q.dequeue();
clazz = current.first;
visited.insert(clazz);
@@ -195,16 +208,19 @@ void CppClass::lookupBases(Symbol *declaration, const LookupContext &context)
}
}
void CppClass::lookupDerived(Symbol *declaration, const Snapshot &snapshot)
void CppClass::lookupDerived(QFutureInterfaceBase &futureInterface,
Symbol *declaration, const Snapshot &snapshot)
{
using Data = QPair<CppClass*, CppTools::TypeHierarchy>;
CppTools::TypeHierarchyBuilder builder(declaration, snapshot);
const CppTools::TypeHierarchy &completeHierarchy = builder.buildDerivedTypeHierarchy();
const CppTools::TypeHierarchy &completeHierarchy = builder.buildDerivedTypeHierarchy(futureInterface);
QQueue<Data> q;
q.enqueue(qMakePair(this, completeHierarchy));
while (!q.isEmpty()) {
if (futureInterface.isCanceled())
return;
const Data &current = q.dequeue();
CppClass *clazz = current.first;
const CppTools::TypeHierarchy &classHierarchy = current.second;
@@ -345,18 +361,43 @@ void CppElementEvaluator::setLookupBaseClasses(const bool lookup)
void CppElementEvaluator::setLookupDerivedClasses(const bool lookup)
{ m_lookupDerivedClasses = lookup; }
// @todo: Consider refactoring code from CppEditor::findLinkAt into here.
// special case for bug QTCREATORBUG-4780
static bool shouldOmitElement(const LookupItem &lookupItem, const Scope *scope)
{
return !lookupItem.declaration() && scope && scope->isFunction()
&& lookupItem.type().match(scope->asFunction()->returnType());
}
void CppElementEvaluator::execute()
{
execute(&CppElementEvaluator::syncExec);
}
QFuture<QSharedPointer<CppElement>> CppElementEvaluator::asyncExecute()
{
return execute(&CppElementEvaluator::asyncExec);
}
static QFuture<QSharedPointer<CppElement>> createFinishedFuture()
{
QFutureInterface<QSharedPointer<CppElement>> futureInterface;
futureInterface.reportStarted();
futureInterface.reportFinished();
return futureInterface.future();
}
// @todo: Consider refactoring code from CppEditor::findLinkAt into here.
QFuture<QSharedPointer<CppElement>> CppElementEvaluator::execute(ExecFunction execFuntion)
{
clear();
if (!m_modelManager)
return;
return createFinishedFuture();
const Snapshot &snapshot = m_modelManager->snapshot();
Document::Ptr doc = snapshot.document(m_editor->textDocument()->filePath());
if (!doc)
return;
return createFinishedFuture();
int line = 0;
int column = 0;
@@ -365,25 +406,52 @@ void CppElementEvaluator::execute()
checkDiagnosticMessage(pos);
if (!matchIncludeFile(doc, line) && !matchMacroInUse(doc, pos)) {
CppTools::moveCursorToEndOfIdentifier(&m_tc);
if (matchIncludeFile(doc, line) || matchMacroInUse(doc, pos))
return createFinishedFuture();
// Fetch the expression's code
ExpressionUnderCursor expressionUnderCursor(doc->languageFeatures());
const QString &expression = expressionUnderCursor(m_tc);
Scope *scope = doc->scopeAt(line, column - 1);
CppTools::moveCursorToEndOfIdentifier(&m_tc);
TypeOfExpression typeOfExpression;
typeOfExpression.init(doc, snapshot);
// make possible to instantiate templates
typeOfExpression.setExpandTemplates(true);
const QList<LookupItem> &lookupItems = typeOfExpression(expression.toUtf8(), scope);
if (lookupItems.isEmpty())
return;
// Fetch the expression's code
ExpressionUnderCursor expressionUnderCursor(doc->languageFeatures());
const QString &expression = expressionUnderCursor(m_tc);
Scope *scope = doc->scopeAt(line, column - 1);
const LookupItem &lookupItem = lookupItems.first(); // ### TODO: select best candidate.
handleLookupItemMatch(snapshot, lookupItem, typeOfExpression.context(), scope);
}
TypeOfExpression typeOfExpression;
typeOfExpression.init(doc, snapshot);
// make possible to instantiate templates
typeOfExpression.setExpandTemplates(true);
const QList<LookupItem> &lookupItems = typeOfExpression(expression.toUtf8(), scope);
if (lookupItems.isEmpty())
return createFinishedFuture();
const LookupItem &lookupItem = lookupItems.first(); // ### TODO: select best candidate.
if (shouldOmitElement(lookupItem, scope))
return createFinishedFuture();
return std::invoke(execFuntion, this, snapshot, lookupItem, typeOfExpression.context());
}
QFuture<QSharedPointer<CppElement>> CppElementEvaluator::syncExec(
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::LookupItem &lookupItem,
const CPlusPlus::LookupContext &lookupContext)
{
QFutureInterface<QSharedPointer<CppElement>> futureInterface;
futureInterface.reportStarted();
handleLookupItemMatch(futureInterface, snapshot, lookupItem, lookupContext,
*m_modelManager->symbolFinder(),
m_lookupBaseClasses, m_lookupDerivedClasses);
futureInterface.reportFinished();
QFuture<QSharedPointer<CppElement>> future = futureInterface.future();
m_element = future.result();
return future;
}
QFuture<QSharedPointer<CppElement>> CppElementEvaluator::asyncExec(
const CPlusPlus::Snapshot &snapshot, const CPlusPlus::LookupItem &lookupItem,
const CPlusPlus::LookupContext &lookupContext)
{
return Utils::runAsync(&handleLookupItemMatch, snapshot, lookupItem, lookupContext,
*m_modelManager->symbolFinder(),
m_lookupBaseClasses, m_lookupDerivedClasses);
}
void CppElementEvaluator::checkDiagnosticMessage(int pos)
@@ -422,24 +490,25 @@ bool CppElementEvaluator::matchMacroInUse(const Document::Ptr &document, int pos
return false;
}
void CppElementEvaluator::handleLookupItemMatch(const Snapshot &snapshot,
const LookupItem &lookupItem,
const LookupContext &context,
const Scope *scope)
static void handleLookupItemMatch(QFutureInterface<QSharedPointer<CppElement>> &futureInterface,
const Snapshot &snapshot,
const LookupItem &lookupItem,
const LookupContext &context,
CppTools::SymbolFinder symbolFinder,
bool lookupBaseClasses,
bool lookupDerivedClasses)
{
if (futureInterface.isCanceled())
return;
QSharedPointer<CppElement> element;
Symbol *declaration = lookupItem.declaration();
if (!declaration) {
const QString &type = Overview().prettyType(lookupItem.type(), QString());
// special case for bug QTCREATORBUG-4780
if (scope && scope->isFunction()
&& lookupItem.type().match(scope->asFunction()->returnType())) {
return;
}
m_element = QSharedPointer<CppElement>(new Unknown(type));
element = QSharedPointer<CppElement>(new Unknown(type));
} else {
const FullySpecifiedType &type = declaration->type();
if (declaration->isNamespace()) {
m_element = QSharedPointer<CppElement>(new CppNamespace(declaration));
element = QSharedPointer<CppElement>(new CppNamespace(declaration));
} else if (declaration->isClass()
|| declaration->isForwardClassDeclaration()
|| (declaration->isTemplate() && declaration->asTemplate()->declaration()
@@ -447,8 +516,7 @@ void CppElementEvaluator::handleLookupItemMatch(const Snapshot &snapshot,
|| declaration->asTemplate()->declaration()->isForwardClassDeclaration()))) {
LookupContext contextToUse = context;
if (declaration->isForwardClassDeclaration()) {
const auto symbolFinder = m_modelManager->symbolFinder();
Symbol *classDeclaration = symbolFinder->findMatchingClassDeclaration(declaration,
Symbol *classDeclaration = symbolFinder.findMatchingClassDeclaration(declaration,
snapshot);
if (classDeclaration) {
declaration = classDeclaration;
@@ -460,29 +528,36 @@ void CppElementEvaluator::handleLookupItemMatch(const Snapshot &snapshot,
}
}
if (futureInterface.isCanceled())
return;
auto cppClass = new CppClass(declaration);
if (m_lookupBaseClasses)
cppClass->lookupBases(declaration, contextToUse);
if (m_lookupDerivedClasses)
cppClass->lookupDerived(declaration, snapshot);
m_element = QSharedPointer<CppElement>(cppClass);
if (lookupBaseClasses)
cppClass->lookupBases(futureInterface, declaration, contextToUse);
if (futureInterface.isCanceled())
return;
if (lookupDerivedClasses)
cppClass->lookupDerived(futureInterface, declaration, snapshot);
if (futureInterface.isCanceled())
return;
element = QSharedPointer<CppElement>(cppClass);
} else if (Enum *enumDecl = declaration->asEnum()) {
m_element = QSharedPointer<CppElement>(new CppEnum(enumDecl));
element = QSharedPointer<CppElement>(new CppEnum(enumDecl));
} else if (auto enumerator = dynamic_cast<EnumeratorDeclaration *>(declaration)) {
m_element = QSharedPointer<CppElement>(new CppEnumerator(enumerator));
element = QSharedPointer<CppElement>(new CppEnumerator(enumerator));
} else if (declaration->isTypedef()) {
m_element = QSharedPointer<CppElement>(new CppTypedef(declaration));
element = QSharedPointer<CppElement>(new CppTypedef(declaration));
} else if (declaration->isFunction()
|| (type.isValid() && type->isFunctionType())
|| declaration->isTemplate()) {
m_element = QSharedPointer<CppElement>(new CppFunction(declaration));
element = QSharedPointer<CppElement>(new CppFunction(declaration));
} else if (declaration->isDeclaration() && type.isValid()) {
m_element = QSharedPointer<CppElement>(
element = QSharedPointer<CppElement>(
new CppVariable(declaration, context, lookupItem.scope()));
} else {
m_element = QSharedPointer<CppElement>(new CppDeclarableElement(declaration));
element = QSharedPointer<CppElement>(new CppDeclarableElement(declaration));
}
}
futureInterface.reportResult(element);
}
bool CppElementEvaluator::identifiedCppElement() const

View File

@@ -32,11 +32,12 @@
#include <cplusplus/CppDocument.h>
#include <QFuture>
#include <QIcon>
#include <QSharedPointer>
#include <QString>
#include <QStringList>
#include <QSharedPointer>
#include <QTextCursor>
#include <QIcon>
namespace CPlusPlus {
class LookupItem;
@@ -57,6 +58,7 @@ public:
void setLookupDerivedClasses(const bool lookup);
void execute();
QFuture<QSharedPointer<CppElement>> asyncExecute();
bool identifiedCppElement() const;
const QSharedPointer<CppElement> &cppElement() const;
bool hasDiagnosis() const;
@@ -64,13 +66,18 @@ public:
private:
void clear();
using ExecFunction = QFuture<QSharedPointer<CppElement>>(CppElementEvaluator::*)
(const CPlusPlus::Snapshot &, const CPlusPlus::LookupItem &,
const CPlusPlus::LookupContext &);
QFuture<QSharedPointer<CppElement>> execute(ExecFunction execFuntion);
QFuture<QSharedPointer<CppElement>> syncExec(const CPlusPlus::Snapshot &,
const CPlusPlus::LookupItem &, const CPlusPlus::LookupContext &);
QFuture<QSharedPointer<CppElement>> asyncExec(const CPlusPlus::Snapshot &,
const CPlusPlus::LookupItem &, const CPlusPlus::LookupContext &);
void checkDiagnosticMessage(int pos);
bool matchIncludeFile(const CPlusPlus::Document::Ptr &document, int line);
bool matchMacroInUse(const CPlusPlus::Document::Ptr &document, int pos);
void handleLookupItemMatch(const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::LookupItem &lookupItem,
const CPlusPlus::LookupContext &lookupContext,
const CPlusPlus::Scope *scope);
TextEditor::TextEditorWidget *m_editor;
CppTools::CppModelManager *m_modelManager;
@@ -123,8 +130,10 @@ public:
CppClass *toCppClass() final;
void lookupBases(CPlusPlus::Symbol *declaration, const CPlusPlus::LookupContext &context);
void lookupDerived(CPlusPlus::Symbol *declaration, const CPlusPlus::Snapshot &snapshot);
void lookupBases(QFutureInterfaceBase &futureInterface,
CPlusPlus::Symbol *declaration, const CPlusPlus::LookupContext &context);
void lookupDerived(QFutureInterfaceBase &futureInterface,
CPlusPlus::Symbol *declaration, const CPlusPlus::Snapshot &snapshot);
public:
QList<CppClass> bases;

View File

@@ -52,7 +52,7 @@ public:
bool visit(CPlusPlus::Class *) override;
const QList<CPlusPlus::Symbol *> &derived() { return _derived; }
const QStringList otherBases() { return _otherBases; }
const QSet<QString> otherBases() { return _otherBases; }
private:
CPlusPlus::LookupContext _context;
@@ -60,7 +60,7 @@ private:
QString _unqualifiedName;
CPlusPlus::Overview _overview;
QHash<CPlusPlus::Symbol *, QString> _actualBases;
QStringList _otherBases;
QSet<QString> _otherBases;
QList<CPlusPlus::Symbol *> _derived;
};
@@ -111,7 +111,7 @@ bool DerivedHierarchyVisitor::visit(CPlusPlus::Class *symbol)
if (_qualifiedName == baseName)
_derived.append(symbol);
else
_otherBases.append(baseName);
_otherBases.insert(baseName);
}
return true;
@@ -146,15 +146,22 @@ void TypeHierarchyBuilder::reset()
}
TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy()
{
QFutureInterfaceBase dummy;
return buildDerivedTypeHierarchy(dummy);
}
TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy(QFutureInterfaceBase &futureInterface)
{
reset();
TypeHierarchy hierarchy(_symbol);
buildDerived(&hierarchy, filesDependingOn(_symbol));
buildDerived(futureInterface, &hierarchy, filesDependingOn(_symbol));
return hierarchy;
}
void TypeHierarchyBuilder::buildDerived(TypeHierarchy *typeHierarchy,
const QStringList &dependingFiles)
void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface,
TypeHierarchy *typeHierarchy,
const QStringList &dependingFiles, int depth)
{
CPlusPlus::Symbol *symbol = typeHierarchy->_symbol;
if (_visited.contains(symbol))
@@ -165,7 +172,15 @@ void TypeHierarchyBuilder::buildDerived(TypeHierarchy *typeHierarchy,
const QString &symbolName = _overview.prettyName(CPlusPlus::LookupContext::fullyQualifiedName(symbol));
DerivedHierarchyVisitor visitor(symbolName);
foreach (const QString &fileName, dependingFiles) {
if (depth == 0)
futureInterface.setProgressRange(0, dependingFiles.size());
int i = -1;
for (const QString &fileName : dependingFiles) {
if (futureInterface.isCanceled())
return;
if (depth == 0)
futureInterface.setProgressValue(++i);
CPlusPlus::Document::Ptr doc = _snapshot.document(fileName);
if ((_candidates.contains(fileName) && !_candidates.value(fileName).contains(symbolName))
|| !doc->control()->findIdentifier(symbol->identifier()->chars(),
@@ -174,14 +189,14 @@ void TypeHierarchyBuilder::buildDerived(TypeHierarchy *typeHierarchy,
}
visitor.execute(doc, _snapshot);
_candidates.insert(fileName, QSet<QString>());
_candidates.insert(fileName, visitor.otherBases());
foreach (const QString &candidate, visitor.otherBases())
_candidates[fileName].insert(candidate);
foreach (CPlusPlus::Symbol *s, visitor.derived()) {
const QList<CPlusPlus::Symbol *> &derived = visitor.derived();
for (CPlusPlus::Symbol *s : derived) {
TypeHierarchy derivedHierarchy(s);
buildDerived(&derivedHierarchy, filesDependingOn(s));
buildDerived(futureInterface, &derivedHierarchy, filesDependingOn(s), depth + 1);
if (futureInterface.isCanceled())
return;
typeHierarchy->_hierarchy.append(derivedHierarchy);
}
}
@@ -193,9 +208,10 @@ QStringList TypeHierarchyBuilder::filesDependingOn(CPlusPlus::Symbol *symbol) co
if (!symbol)
return deps;
Utils::FilePath file = Utils::FilePath::fromUtf8(symbol->fileName(), symbol->fileNameLength());
const Utils::FilePath file = Utils::FilePath::fromUtf8(symbol->fileName(), symbol->fileNameLength());
deps << file.toString();
foreach (const Utils::FilePath &fileName, _snapshot.filesDependingOn(file))
const Utils::FilePaths filePaths = _snapshot.filesDependingOn(file);
for (const Utils::FilePath &fileName : filePaths)
deps.append(fileName.toString());
return deps;
}

View File

@@ -30,6 +30,7 @@
#include <cplusplus/CppDocument.h>
#include <cplusplus/Overview.h>
#include <QFutureInterface>
#include <QList>
#include <QSet>
@@ -60,10 +61,12 @@ public:
TypeHierarchyBuilder(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot);
TypeHierarchy buildDerivedTypeHierarchy();
TypeHierarchy buildDerivedTypeHierarchy(QFutureInterfaceBase &futureInterface);
private:
void reset();
void buildDerived(TypeHierarchy *typeHierarchy, const QStringList &dependencies);
void buildDerived(QFutureInterfaceBase &futureInterface,
TypeHierarchy *typeHierarchy, const QStringList &dependencies, int depth = 0);
QStringList filesDependingOn(CPlusPlus::Symbol *symbol) const;
CPlusPlus::Symbol *_symbol;