forked from qt-creator/qt-creator
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:
@@ -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();
|
||||
|
@@ -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
|
||||
|
@@ -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 ¤t = 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
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user