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/find/itemviewfind.h>
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
|
#include <coreplugin/progressmanager/progressmanager.h>
|
||||||
#include <cpptools/cppelementevaluator.h>
|
#include <cpptools/cppelementevaluator.h>
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/delegates.h>
|
#include <utils/delegates.h>
|
||||||
#include <utils/navigationtreeview.h>
|
|
||||||
#include <utils/dropsupport.h>
|
#include <utils/dropsupport.h>
|
||||||
|
#include <utils/navigationtreeview.h>
|
||||||
|
#include <utils/progressindicator.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
@@ -107,10 +109,10 @@ CppTypeHierarchyWidget::CppTypeHierarchyWidget()
|
|||||||
m_treeView->setDefaultDropAction(Qt::MoveAction);
|
m_treeView->setDefaultDropAction(Qt::MoveAction);
|
||||||
connect(m_treeView, &QTreeView::activated, this, &CppTypeHierarchyWidget::onItemActivated);
|
connect(m_treeView, &QTreeView::activated, this, &CppTypeHierarchyWidget::onItemActivated);
|
||||||
|
|
||||||
m_noTypeHierarchyAvailableLabel = new QLabel(tr("No type hierarchy available"), this);
|
m_infoLabel = new QLabel(this);
|
||||||
m_noTypeHierarchyAvailableLabel->setAlignment(Qt::AlignCenter);
|
m_infoLabel->setAlignment(Qt::AlignCenter);
|
||||||
m_noTypeHierarchyAvailableLabel->setAutoFillBackground(true);
|
m_infoLabel->setAutoFillBackground(true);
|
||||||
m_noTypeHierarchyAvailableLabel->setBackgroundRole(QPalette::Base);
|
m_infoLabel->setBackgroundRole(QPalette::Base);
|
||||||
|
|
||||||
m_hierarchyWidget = new QWidget(this);
|
m_hierarchyWidget = new QWidget(this);
|
||||||
auto layout = new QVBoxLayout;
|
auto layout = new QVBoxLayout;
|
||||||
@@ -122,37 +124,72 @@ CppTypeHierarchyWidget::CppTypeHierarchyWidget()
|
|||||||
|
|
||||||
m_stackLayout = new QStackedLayout;
|
m_stackLayout = new QStackedLayout;
|
||||||
m_stackLayout->addWidget(m_hierarchyWidget);
|
m_stackLayout->addWidget(m_hierarchyWidget);
|
||||||
m_stackLayout->addWidget(m_noTypeHierarchyAvailableLabel);
|
m_stackLayout->addWidget(m_infoLabel);
|
||||||
m_stackLayout->setCurrentWidget(m_noTypeHierarchyAvailableLabel);
|
showNoTypeHierarchyLabel();
|
||||||
setLayout(m_stackLayout);
|
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()
|
void CppTypeHierarchyWidget::perform()
|
||||||
{
|
{
|
||||||
showNoTypeHierarchyLabel();
|
if (m_future.isRunning())
|
||||||
|
m_future.cancel();
|
||||||
|
|
||||||
auto editor = qobject_cast<CppEditor *>(Core::EditorManager::currentEditor());
|
auto editor = qobject_cast<CppEditor *>(Core::EditorManager::currentEditor());
|
||||||
if (!editor)
|
if (!editor) {
|
||||||
|
showNoTypeHierarchyLabel();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto widget = qobject_cast<CppEditorWidget *>(editor->widget());
|
auto widget = qobject_cast<CppEditorWidget *>(editor->widget());
|
||||||
if (!widget)
|
if (!widget) {
|
||||||
|
showNoTypeHierarchyLabel();
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
clearTypeHierarchy();
|
showProgress();
|
||||||
|
|
||||||
CppElementEvaluator evaluator(widget);
|
CppElementEvaluator evaluator(widget);
|
||||||
evaluator.setLookupBaseClasses(true);
|
evaluator.setLookupBaseClasses(true);
|
||||||
evaluator.setLookupDerivedClasses(true);
|
evaluator.setLookupDerivedClasses(true);
|
||||||
evaluator.execute();
|
m_future = evaluator.asyncExecute();
|
||||||
if (evaluator.identifiedCppElement()) {
|
m_futureWatcher.setFuture(m_future);
|
||||||
const QSharedPointer<CppElement> &cppElement = evaluator.cppElement();
|
|
||||||
CppElement *element = cppElement.data();
|
Core::ProgressManager::addTask(m_future, tr("Evaluating Type Hierarchy"), "TypeHierarchy");
|
||||||
if (CppClass *cppClass = element->toCppClass()) {
|
}
|
||||||
|
|
||||||
|
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->setText(cppClass->name);
|
||||||
m_inspectedClass->setLink(cppClass->link);
|
m_inspectedClass->setLink(cppClass->link);
|
||||||
QStandardItem *bases = new QStandardItem(tr("Bases"));
|
QStandardItem *bases = new QStandardItem(tr("Bases"));
|
||||||
@@ -165,8 +202,6 @@ void CppTypeHierarchyWidget::perform()
|
|||||||
|
|
||||||
showTypeHierarchy();
|
showTypeHierarchy();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CppTypeHierarchyWidget::buildHierarchy(const CppClass &cppClass, QStandardItem *parent,
|
void CppTypeHierarchyWidget::buildHierarchy(const CppClass &cppClass, QStandardItem *parent,
|
||||||
bool isRoot, const HierarchyMember member)
|
bool isRoot, const HierarchyMember member)
|
||||||
@@ -182,7 +217,8 @@ void CppTypeHierarchyWidget::buildHierarchy(const CppClass &cppClass, QStandardI
|
|||||||
|
|
||||||
void CppTypeHierarchyWidget::showNoTypeHierarchyLabel()
|
void CppTypeHierarchyWidget::showNoTypeHierarchyLabel()
|
||||||
{
|
{
|
||||||
m_stackLayout->setCurrentWidget(m_noTypeHierarchyAvailableLabel);
|
m_infoLabel->setText(tr("No type hierarchy available"));
|
||||||
|
m_stackLayout->setCurrentWidget(m_infoLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppTypeHierarchyWidget::showTypeHierarchy()
|
void CppTypeHierarchyWidget::showTypeHierarchy()
|
||||||
@@ -190,6 +226,22 @@ void CppTypeHierarchyWidget::showTypeHierarchy()
|
|||||||
m_stackLayout->setCurrentWidget(m_hierarchyWidget);
|
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()
|
void CppTypeHierarchyWidget::clearTypeHierarchy()
|
||||||
{
|
{
|
||||||
m_inspectedClass->clear();
|
m_inspectedClass->clear();
|
||||||
|
@@ -27,11 +27,14 @@
|
|||||||
|
|
||||||
#include <coreplugin/inavigationwidgetfactory.h>
|
#include <coreplugin/inavigationwidgetfactory.h>
|
||||||
|
|
||||||
|
#include <QFuture>
|
||||||
|
#include <QFutureWatcher>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QString>
|
#include <QSharedPointer>
|
||||||
#include <QWidget>
|
|
||||||
#include <QStackedWidget>
|
#include <QStackedWidget>
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
|
#include <QString>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QLabel;
|
class QLabel;
|
||||||
@@ -43,11 +46,12 @@ QT_END_NAMESPACE
|
|||||||
namespace TextEditor { class TextEditorLinkLabel; }
|
namespace TextEditor { class TextEditorLinkLabel; }
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
class NavigationTreeView;
|
|
||||||
class AnnotatedItemDelegate;
|
class AnnotatedItemDelegate;
|
||||||
|
class NavigationTreeView;
|
||||||
|
class ProgressIndicator;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace CppTools { class CppClass; }
|
namespace CppTools { class CppClass; class CppElement; }
|
||||||
|
|
||||||
namespace CppEditor {
|
namespace CppEditor {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
@@ -75,12 +79,17 @@ public:
|
|||||||
|
|
||||||
void perform();
|
void perform();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void displayHierarchy();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef QList<CppTools::CppClass> CppTools::CppClass::*HierarchyMember;
|
typedef QList<CppTools::CppClass> CppTools::CppClass::*HierarchyMember;
|
||||||
void buildHierarchy(const CppTools::CppClass &cppClass, QStandardItem *parent,
|
void buildHierarchy(const CppTools::CppClass &cppClass, QStandardItem *parent,
|
||||||
bool isRoot, HierarchyMember member);
|
bool isRoot, HierarchyMember member);
|
||||||
void showNoTypeHierarchyLabel();
|
void showNoTypeHierarchyLabel();
|
||||||
void showTypeHierarchy();
|
void showTypeHierarchy();
|
||||||
|
void showProgress();
|
||||||
|
void hideProgress();
|
||||||
void clearTypeHierarchy();
|
void clearTypeHierarchy();
|
||||||
void onItemActivated(const QModelIndex &index);
|
void onItemActivated(const QModelIndex &index);
|
||||||
|
|
||||||
@@ -91,7 +100,10 @@ private:
|
|||||||
QStandardItemModel *m_model = nullptr;
|
QStandardItemModel *m_model = nullptr;
|
||||||
Utils::AnnotatedItemDelegate *m_delegate = nullptr;
|
Utils::AnnotatedItemDelegate *m_delegate = nullptr;
|
||||||
TextEditor::TextEditorLinkLabel *m_inspectedClass = 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
|
class CppTypeHierarchyFactory : public Core::INavigationWidgetFactory
|
||||||
|
@@ -36,6 +36,8 @@
|
|||||||
#include <cplusplus/Icons.h>
|
#include <cplusplus/Icons.h>
|
||||||
#include <cplusplus/TypeOfExpression.h>
|
#include <cplusplus/TypeOfExpression.h>
|
||||||
|
|
||||||
|
#include <utils/runextensions.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QQueue>
|
#include <QQueue>
|
||||||
@@ -44,6 +46,14 @@ using namespace CPlusPlus;
|
|||||||
|
|
||||||
namespace CppTools {
|
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)
|
static QStringList stripName(const QString &name)
|
||||||
{
|
{
|
||||||
QStringList all;
|
QStringList all;
|
||||||
@@ -164,7 +174,8 @@ CppClass *CppClass::toCppClass()
|
|||||||
return this;
|
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*>;
|
using Data = QPair<ClassOrNamespace*, CppClass*>;
|
||||||
|
|
||||||
@@ -174,6 +185,8 @@ void CppClass::lookupBases(Symbol *declaration, const LookupContext &context)
|
|||||||
QQueue<Data> q;
|
QQueue<Data> q;
|
||||||
q.enqueue(qMakePair(clazz, this));
|
q.enqueue(qMakePair(clazz, this));
|
||||||
while (!q.isEmpty()) {
|
while (!q.isEmpty()) {
|
||||||
|
if (futureInterface.isCanceled())
|
||||||
|
return;
|
||||||
Data current = q.dequeue();
|
Data current = q.dequeue();
|
||||||
clazz = current.first;
|
clazz = current.first;
|
||||||
visited.insert(clazz);
|
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>;
|
using Data = QPair<CppClass*, CppTools::TypeHierarchy>;
|
||||||
|
|
||||||
CppTools::TypeHierarchyBuilder builder(declaration, snapshot);
|
CppTools::TypeHierarchyBuilder builder(declaration, snapshot);
|
||||||
const CppTools::TypeHierarchy &completeHierarchy = builder.buildDerivedTypeHierarchy();
|
const CppTools::TypeHierarchy &completeHierarchy = builder.buildDerivedTypeHierarchy(futureInterface);
|
||||||
|
|
||||||
QQueue<Data> q;
|
QQueue<Data> q;
|
||||||
q.enqueue(qMakePair(this, completeHierarchy));
|
q.enqueue(qMakePair(this, completeHierarchy));
|
||||||
while (!q.isEmpty()) {
|
while (!q.isEmpty()) {
|
||||||
|
if (futureInterface.isCanceled())
|
||||||
|
return;
|
||||||
const Data ¤t = q.dequeue();
|
const Data ¤t = q.dequeue();
|
||||||
CppClass *clazz = current.first;
|
CppClass *clazz = current.first;
|
||||||
const CppTools::TypeHierarchy &classHierarchy = current.second;
|
const CppTools::TypeHierarchy &classHierarchy = current.second;
|
||||||
@@ -345,18 +361,43 @@ void CppElementEvaluator::setLookupBaseClasses(const bool lookup)
|
|||||||
void CppElementEvaluator::setLookupDerivedClasses(const bool lookup)
|
void CppElementEvaluator::setLookupDerivedClasses(const bool lookup)
|
||||||
{ m_lookupDerivedClasses = 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()
|
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();
|
clear();
|
||||||
|
|
||||||
if (!m_modelManager)
|
if (!m_modelManager)
|
||||||
return;
|
return createFinishedFuture();
|
||||||
|
|
||||||
const Snapshot &snapshot = m_modelManager->snapshot();
|
const Snapshot &snapshot = m_modelManager->snapshot();
|
||||||
Document::Ptr doc = snapshot.document(m_editor->textDocument()->filePath());
|
Document::Ptr doc = snapshot.document(m_editor->textDocument()->filePath());
|
||||||
if (!doc)
|
if (!doc)
|
||||||
return;
|
return createFinishedFuture();
|
||||||
|
|
||||||
int line = 0;
|
int line = 0;
|
||||||
int column = 0;
|
int column = 0;
|
||||||
@@ -365,7 +406,9 @@ void CppElementEvaluator::execute()
|
|||||||
|
|
||||||
checkDiagnosticMessage(pos);
|
checkDiagnosticMessage(pos);
|
||||||
|
|
||||||
if (!matchIncludeFile(doc, line) && !matchMacroInUse(doc, pos)) {
|
if (matchIncludeFile(doc, line) || matchMacroInUse(doc, pos))
|
||||||
|
return createFinishedFuture();
|
||||||
|
|
||||||
CppTools::moveCursorToEndOfIdentifier(&m_tc);
|
CppTools::moveCursorToEndOfIdentifier(&m_tc);
|
||||||
|
|
||||||
// Fetch the expression's code
|
// Fetch the expression's code
|
||||||
@@ -379,11 +422,36 @@ void CppElementEvaluator::execute()
|
|||||||
typeOfExpression.setExpandTemplates(true);
|
typeOfExpression.setExpandTemplates(true);
|
||||||
const QList<LookupItem> &lookupItems = typeOfExpression(expression.toUtf8(), scope);
|
const QList<LookupItem> &lookupItems = typeOfExpression(expression.toUtf8(), scope);
|
||||||
if (lookupItems.isEmpty())
|
if (lookupItems.isEmpty())
|
||||||
return;
|
return createFinishedFuture();
|
||||||
|
|
||||||
const LookupItem &lookupItem = lookupItems.first(); // ### TODO: select best candidate.
|
const LookupItem &lookupItem = lookupItems.first(); // ### TODO: select best candidate.
|
||||||
handleLookupItemMatch(snapshot, lookupItem, typeOfExpression.context(), scope);
|
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)
|
void CppElementEvaluator::checkDiagnosticMessage(int pos)
|
||||||
@@ -422,24 +490,25 @@ bool CppElementEvaluator::matchMacroInUse(const Document::Ptr &document, int pos
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppElementEvaluator::handleLookupItemMatch(const Snapshot &snapshot,
|
static void handleLookupItemMatch(QFutureInterface<QSharedPointer<CppElement>> &futureInterface,
|
||||||
|
const Snapshot &snapshot,
|
||||||
const LookupItem &lookupItem,
|
const LookupItem &lookupItem,
|
||||||
const LookupContext &context,
|
const LookupContext &context,
|
||||||
const Scope *scope)
|
CppTools::SymbolFinder symbolFinder,
|
||||||
|
bool lookupBaseClasses,
|
||||||
|
bool lookupDerivedClasses)
|
||||||
{
|
{
|
||||||
|
if (futureInterface.isCanceled())
|
||||||
|
return;
|
||||||
|
QSharedPointer<CppElement> element;
|
||||||
Symbol *declaration = lookupItem.declaration();
|
Symbol *declaration = lookupItem.declaration();
|
||||||
if (!declaration) {
|
if (!declaration) {
|
||||||
const QString &type = Overview().prettyType(lookupItem.type(), QString());
|
const QString &type = Overview().prettyType(lookupItem.type(), QString());
|
||||||
// special case for bug QTCREATORBUG-4780
|
element = QSharedPointer<CppElement>(new Unknown(type));
|
||||||
if (scope && scope->isFunction()
|
|
||||||
&& lookupItem.type().match(scope->asFunction()->returnType())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_element = QSharedPointer<CppElement>(new Unknown(type));
|
|
||||||
} else {
|
} else {
|
||||||
const FullySpecifiedType &type = declaration->type();
|
const FullySpecifiedType &type = declaration->type();
|
||||||
if (declaration->isNamespace()) {
|
if (declaration->isNamespace()) {
|
||||||
m_element = QSharedPointer<CppElement>(new CppNamespace(declaration));
|
element = QSharedPointer<CppElement>(new CppNamespace(declaration));
|
||||||
} else if (declaration->isClass()
|
} else if (declaration->isClass()
|
||||||
|| declaration->isForwardClassDeclaration()
|
|| declaration->isForwardClassDeclaration()
|
||||||
|| (declaration->isTemplate() && declaration->asTemplate()->declaration()
|
|| (declaration->isTemplate() && declaration->asTemplate()->declaration()
|
||||||
@@ -447,8 +516,7 @@ void CppElementEvaluator::handleLookupItemMatch(const Snapshot &snapshot,
|
|||||||
|| declaration->asTemplate()->declaration()->isForwardClassDeclaration()))) {
|
|| declaration->asTemplate()->declaration()->isForwardClassDeclaration()))) {
|
||||||
LookupContext contextToUse = context;
|
LookupContext contextToUse = context;
|
||||||
if (declaration->isForwardClassDeclaration()) {
|
if (declaration->isForwardClassDeclaration()) {
|
||||||
const auto symbolFinder = m_modelManager->symbolFinder();
|
Symbol *classDeclaration = symbolFinder.findMatchingClassDeclaration(declaration,
|
||||||
Symbol *classDeclaration = symbolFinder->findMatchingClassDeclaration(declaration,
|
|
||||||
snapshot);
|
snapshot);
|
||||||
if (classDeclaration) {
|
if (classDeclaration) {
|
||||||
declaration = classDeclaration;
|
declaration = classDeclaration;
|
||||||
@@ -460,29 +528,36 @@ void CppElementEvaluator::handleLookupItemMatch(const Snapshot &snapshot,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (futureInterface.isCanceled())
|
||||||
|
return;
|
||||||
auto cppClass = new CppClass(declaration);
|
auto cppClass = new CppClass(declaration);
|
||||||
if (m_lookupBaseClasses)
|
if (lookupBaseClasses)
|
||||||
cppClass->lookupBases(declaration, contextToUse);
|
cppClass->lookupBases(futureInterface, declaration, contextToUse);
|
||||||
if (m_lookupDerivedClasses)
|
if (futureInterface.isCanceled())
|
||||||
cppClass->lookupDerived(declaration, snapshot);
|
return;
|
||||||
m_element = QSharedPointer<CppElement>(cppClass);
|
if (lookupDerivedClasses)
|
||||||
|
cppClass->lookupDerived(futureInterface, declaration, snapshot);
|
||||||
|
if (futureInterface.isCanceled())
|
||||||
|
return;
|
||||||
|
element = QSharedPointer<CppElement>(cppClass);
|
||||||
} else if (Enum *enumDecl = declaration->asEnum()) {
|
} 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)) {
|
} 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()) {
|
} else if (declaration->isTypedef()) {
|
||||||
m_element = QSharedPointer<CppElement>(new CppTypedef(declaration));
|
element = QSharedPointer<CppElement>(new CppTypedef(declaration));
|
||||||
} else if (declaration->isFunction()
|
} else if (declaration->isFunction()
|
||||||
|| (type.isValid() && type->isFunctionType())
|
|| (type.isValid() && type->isFunctionType())
|
||||||
|| declaration->isTemplate()) {
|
|| declaration->isTemplate()) {
|
||||||
m_element = QSharedPointer<CppElement>(new CppFunction(declaration));
|
element = QSharedPointer<CppElement>(new CppFunction(declaration));
|
||||||
} else if (declaration->isDeclaration() && type.isValid()) {
|
} else if (declaration->isDeclaration() && type.isValid()) {
|
||||||
m_element = QSharedPointer<CppElement>(
|
element = QSharedPointer<CppElement>(
|
||||||
new CppVariable(declaration, context, lookupItem.scope()));
|
new CppVariable(declaration, context, lookupItem.scope()));
|
||||||
} else {
|
} else {
|
||||||
m_element = QSharedPointer<CppElement>(new CppDeclarableElement(declaration));
|
element = QSharedPointer<CppElement>(new CppDeclarableElement(declaration));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
futureInterface.reportResult(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CppElementEvaluator::identifiedCppElement() const
|
bool CppElementEvaluator::identifiedCppElement() const
|
||||||
|
@@ -32,11 +32,12 @@
|
|||||||
|
|
||||||
#include <cplusplus/CppDocument.h>
|
#include <cplusplus/CppDocument.h>
|
||||||
|
|
||||||
|
#include <QFuture>
|
||||||
|
#include <QIcon>
|
||||||
|
#include <QSharedPointer>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QSharedPointer>
|
|
||||||
#include <QTextCursor>
|
#include <QTextCursor>
|
||||||
#include <QIcon>
|
|
||||||
|
|
||||||
namespace CPlusPlus {
|
namespace CPlusPlus {
|
||||||
class LookupItem;
|
class LookupItem;
|
||||||
@@ -57,6 +58,7 @@ public:
|
|||||||
void setLookupDerivedClasses(const bool lookup);
|
void setLookupDerivedClasses(const bool lookup);
|
||||||
|
|
||||||
void execute();
|
void execute();
|
||||||
|
QFuture<QSharedPointer<CppElement>> asyncExecute();
|
||||||
bool identifiedCppElement() const;
|
bool identifiedCppElement() const;
|
||||||
const QSharedPointer<CppElement> &cppElement() const;
|
const QSharedPointer<CppElement> &cppElement() const;
|
||||||
bool hasDiagnosis() const;
|
bool hasDiagnosis() const;
|
||||||
@@ -64,13 +66,18 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void clear();
|
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);
|
void checkDiagnosticMessage(int pos);
|
||||||
bool matchIncludeFile(const CPlusPlus::Document::Ptr &document, int line);
|
bool matchIncludeFile(const CPlusPlus::Document::Ptr &document, int line);
|
||||||
bool matchMacroInUse(const CPlusPlus::Document::Ptr &document, int pos);
|
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;
|
TextEditor::TextEditorWidget *m_editor;
|
||||||
CppTools::CppModelManager *m_modelManager;
|
CppTools::CppModelManager *m_modelManager;
|
||||||
@@ -123,8 +130,10 @@ public:
|
|||||||
|
|
||||||
CppClass *toCppClass() final;
|
CppClass *toCppClass() final;
|
||||||
|
|
||||||
void lookupBases(CPlusPlus::Symbol *declaration, const CPlusPlus::LookupContext &context);
|
void lookupBases(QFutureInterfaceBase &futureInterface,
|
||||||
void lookupDerived(CPlusPlus::Symbol *declaration, const CPlusPlus::Snapshot &snapshot);
|
CPlusPlus::Symbol *declaration, const CPlusPlus::LookupContext &context);
|
||||||
|
void lookupDerived(QFutureInterfaceBase &futureInterface,
|
||||||
|
CPlusPlus::Symbol *declaration, const CPlusPlus::Snapshot &snapshot);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
QList<CppClass> bases;
|
QList<CppClass> bases;
|
||||||
|
@@ -52,7 +52,7 @@ public:
|
|||||||
bool visit(CPlusPlus::Class *) override;
|
bool visit(CPlusPlus::Class *) override;
|
||||||
|
|
||||||
const QList<CPlusPlus::Symbol *> &derived() { return _derived; }
|
const QList<CPlusPlus::Symbol *> &derived() { return _derived; }
|
||||||
const QStringList otherBases() { return _otherBases; }
|
const QSet<QString> otherBases() { return _otherBases; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CPlusPlus::LookupContext _context;
|
CPlusPlus::LookupContext _context;
|
||||||
@@ -60,7 +60,7 @@ private:
|
|||||||
QString _unqualifiedName;
|
QString _unqualifiedName;
|
||||||
CPlusPlus::Overview _overview;
|
CPlusPlus::Overview _overview;
|
||||||
QHash<CPlusPlus::Symbol *, QString> _actualBases;
|
QHash<CPlusPlus::Symbol *, QString> _actualBases;
|
||||||
QStringList _otherBases;
|
QSet<QString> _otherBases;
|
||||||
QList<CPlusPlus::Symbol *> _derived;
|
QList<CPlusPlus::Symbol *> _derived;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ bool DerivedHierarchyVisitor::visit(CPlusPlus::Class *symbol)
|
|||||||
if (_qualifiedName == baseName)
|
if (_qualifiedName == baseName)
|
||||||
_derived.append(symbol);
|
_derived.append(symbol);
|
||||||
else
|
else
|
||||||
_otherBases.append(baseName);
|
_otherBases.insert(baseName);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -146,15 +146,22 @@ void TypeHierarchyBuilder::reset()
|
|||||||
}
|
}
|
||||||
|
|
||||||
TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy()
|
TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy()
|
||||||
|
{
|
||||||
|
QFutureInterfaceBase dummy;
|
||||||
|
return buildDerivedTypeHierarchy(dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeHierarchy TypeHierarchyBuilder::buildDerivedTypeHierarchy(QFutureInterfaceBase &futureInterface)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
TypeHierarchy hierarchy(_symbol);
|
TypeHierarchy hierarchy(_symbol);
|
||||||
buildDerived(&hierarchy, filesDependingOn(_symbol));
|
buildDerived(futureInterface, &hierarchy, filesDependingOn(_symbol));
|
||||||
return hierarchy;
|
return hierarchy;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeHierarchyBuilder::buildDerived(TypeHierarchy *typeHierarchy,
|
void TypeHierarchyBuilder::buildDerived(QFutureInterfaceBase &futureInterface,
|
||||||
const QStringList &dependingFiles)
|
TypeHierarchy *typeHierarchy,
|
||||||
|
const QStringList &dependingFiles, int depth)
|
||||||
{
|
{
|
||||||
CPlusPlus::Symbol *symbol = typeHierarchy->_symbol;
|
CPlusPlus::Symbol *symbol = typeHierarchy->_symbol;
|
||||||
if (_visited.contains(symbol))
|
if (_visited.contains(symbol))
|
||||||
@@ -165,7 +172,15 @@ void TypeHierarchyBuilder::buildDerived(TypeHierarchy *typeHierarchy,
|
|||||||
const QString &symbolName = _overview.prettyName(CPlusPlus::LookupContext::fullyQualifiedName(symbol));
|
const QString &symbolName = _overview.prettyName(CPlusPlus::LookupContext::fullyQualifiedName(symbol));
|
||||||
DerivedHierarchyVisitor visitor(symbolName);
|
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);
|
CPlusPlus::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(),
|
||||||
@@ -174,14 +189,14 @@ void TypeHierarchyBuilder::buildDerived(TypeHierarchy *typeHierarchy,
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitor.execute(doc, _snapshot);
|
visitor.execute(doc, _snapshot);
|
||||||
_candidates.insert(fileName, QSet<QString>());
|
_candidates.insert(fileName, visitor.otherBases());
|
||||||
|
|
||||||
foreach (const QString &candidate, visitor.otherBases())
|
const QList<CPlusPlus::Symbol *> &derived = visitor.derived();
|
||||||
_candidates[fileName].insert(candidate);
|
for (CPlusPlus::Symbol *s : derived) {
|
||||||
|
|
||||||
foreach (CPlusPlus::Symbol *s, visitor.derived()) {
|
|
||||||
TypeHierarchy derivedHierarchy(s);
|
TypeHierarchy derivedHierarchy(s);
|
||||||
buildDerived(&derivedHierarchy, filesDependingOn(s));
|
buildDerived(futureInterface, &derivedHierarchy, filesDependingOn(s), depth + 1);
|
||||||
|
if (futureInterface.isCanceled())
|
||||||
|
return;
|
||||||
typeHierarchy->_hierarchy.append(derivedHierarchy);
|
typeHierarchy->_hierarchy.append(derivedHierarchy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,9 +208,10 @@ QStringList TypeHierarchyBuilder::filesDependingOn(CPlusPlus::Symbol *symbol) co
|
|||||||
if (!symbol)
|
if (!symbol)
|
||||||
return deps;
|
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();
|
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());
|
deps.append(fileName.toString());
|
||||||
return deps;
|
return deps;
|
||||||
}
|
}
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include <cplusplus/CppDocument.h>
|
#include <cplusplus/CppDocument.h>
|
||||||
#include <cplusplus/Overview.h>
|
#include <cplusplus/Overview.h>
|
||||||
|
|
||||||
|
#include <QFutureInterface>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
|
||||||
@@ -60,10 +61,12 @@ public:
|
|||||||
TypeHierarchyBuilder(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot);
|
TypeHierarchyBuilder(CPlusPlus::Symbol *symbol, const CPlusPlus::Snapshot &snapshot);
|
||||||
|
|
||||||
TypeHierarchy buildDerivedTypeHierarchy();
|
TypeHierarchy buildDerivedTypeHierarchy();
|
||||||
|
TypeHierarchy buildDerivedTypeHierarchy(QFutureInterfaceBase &futureInterface);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void reset();
|
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;
|
QStringList filesDependingOn(CPlusPlus::Symbol *symbol) const;
|
||||||
|
|
||||||
CPlusPlus::Symbol *_symbol;
|
CPlusPlus::Symbol *_symbol;
|
||||||
|
Reference in New Issue
Block a user