Commit 11aeaea8 authored by Nikolai Kosjar's avatar Nikolai Kosjar

CppEditor: "Follow Symbol Under Cursor" for virtual functions

F2 on a virtual function call presents a list of overrides in derived
classes. The function declaration of the static type is shown
immediately at the top.

Task-number: QTCREATORBUG-9611

Change-Id: I80ce906fa06272dc9fbd1662cd17500b8c77067f
Reviewed-by: default avatarJoerg Bornemann <joerg.bornemann@digia.com>
parent 3a64f8a3
......@@ -159,7 +159,7 @@ static bool isValidFileNameChar(const QChar &c)
}
CMakeEditorWidget::Link CMakeEditorWidget::findLinkAt(const QTextCursor &cursor,
bool/* resolveTarget*/)
bool/* resolveTarget*/, bool /*inNextSplit*/)
{
Link link;
......
......@@ -78,8 +78,7 @@ public:
CMakeEditorFactory *factory() { return m_factory; }
TextEditor::TextEditorActionHandler *actionHandler() const { return m_ah; }
Link findLinkAt(const QTextCursor &cursor,
bool resolveTarget = true);
Link findLinkAt(const QTextCursor &cursor, bool resolveTarget = true, bool inNextSplit = false);
protected:
TextEditor::BaseTextEditor *createEditor();
......
......@@ -511,6 +511,7 @@ CPPEditorWidget::CPPEditorWidget(QWidget *parent)
, m_firstRenameChange(false)
, m_objcEnabled(false)
, m_commentsSettings(CppTools::CppToolsSettings::instance()->commentsSettings())
, m_followSymbolUnderCursor(new FollowSymbolUnderCursor(this))
{
qRegisterMetaType<SemanticInfo>("CppTools::SemanticInfo");
......@@ -1239,14 +1240,14 @@ QString CPPEditorWidget::identifierUnderCursor(QTextCursor *macroCursor)
return macroCursor->selectedText();
}
CPPEditorWidget::Link CPPEditorWidget::findLinkAt(const QTextCursor &cursor, bool resolveTarget)
CPPEditorWidget::Link CPPEditorWidget::findLinkAt(const QTextCursor &cursor, bool resolveTarget,
bool inNextSplit)
{
if (!m_modelManager)
return Link();
FollowSymbolUnderCursor followSymbolUnderCursor(this, cursor, resolveTarget,
m_modelManager->snapshot(), m_lastSemanticInfo.doc, symbolFinder());
return followSymbolUnderCursor.findLink();
return m_followSymbolUnderCursor->findLink(cursor, resolveTarget, m_modelManager->snapshot(),
m_lastSemanticInfo.doc, symbolFinder(), inNextSplit);
}
unsigned CPPEditorWidget::editorRevision() const
......@@ -1720,6 +1721,8 @@ TextEditor::IAssistInterface *CPPEditorWidget::createAssistInterface(
if (!semanticInfo().doc || isOutdated())
return 0;
return new CppQuickFixAssistInterface(const_cast<CPPEditorWidget *>(this), reason);
} else {
return BaseTextEditorWidget::createAssistInterface(kind, reason);
}
return 0;
}
......@@ -1812,6 +1815,11 @@ void CPPEditorWidget::updateContentsChangedSignal()
this, SLOT(onContentsChanged(int,int,int)));
}
FollowSymbolUnderCursor *CPPEditorWidget::followSymbolUnderCursorDelegate()
{
return m_followSymbolUnderCursor.data();
}
void CPPEditorWidget::abortDeclDefLink()
{
if (!m_declDefLink)
......
......@@ -30,6 +30,7 @@
#ifndef CPPEDITOR_H
#define CPPEDITOR_H
#include "cppfollowsymbolundercursor.h"
#include "cppfunctiondecldeflink.h"
#include <cpptools/commentssettings.h>
......@@ -132,6 +133,8 @@ public:
void updateContentsChangedSignal();
FollowSymbolUnderCursor *followSymbolUnderCursorDelegate(); // exposed for tests
Q_SIGNALS:
void outlineModelIndexChanged(const QModelIndex &index);
......@@ -204,7 +207,7 @@ private:
Q_SLOT void abortDeclDefLink();
Link findLinkAt(const QTextCursor &, bool resolveTarget = true);
Link findLinkAt(const QTextCursor &, bool resolveTarget = true, bool inNextSplit = false);
bool openCppEditorAt(const Link &, bool inNextSplit = false);
QModelIndex indexForPosition(int line, int column,
......@@ -254,6 +257,8 @@ private:
QSharedPointer<FunctionDeclDefLink> m_declDefLink;
CppTools::CommentsSettings m_commentsSettings;
QScopedPointer<FollowSymbolUnderCursor> m_followSymbolUnderCursor;
};
} // namespace Internal
......
......@@ -23,7 +23,8 @@ HEADERS += cppeditorplugin.h \
cppincludehierarchy.h \
cppincludehierarchymodel.h \
cppincludehierarchyitem.h \
cppincludehierarchytreeview.h
cppincludehierarchytreeview.h \
cppvirtualfunctionassistprovider.h
SOURCES += cppeditorplugin.cpp \
cppautocompleter.cpp \
......@@ -45,7 +46,8 @@ SOURCES += cppeditorplugin.cpp \
cppincludehierarchy.cpp \
cppincludehierarchymodel.cpp \
cppincludehierarchyitem.cpp \
cppincludehierarchytreeview.cpp
cppincludehierarchytreeview.cpp \
cppvirtualfunctionassistprovider.cpp
RESOURCES += cppeditor.qrc
......
......@@ -60,6 +60,8 @@ QtcPlugin {
"cppsnippetprovider.h",
"cpptypehierarchy.cpp",
"cpptypehierarchy.h",
"cppvirtualfunctionassistprovider.cpp",
"cppvirtualfunctionassistprovider.h",
]
Group {
......
......@@ -128,6 +128,13 @@ private slots:
void test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_globalNamespace();
void test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_namespace();
void test_FollowSymbolUnderCursor_using_QTCREATORBUG7903_insideFunction();
void test_FollowSymbolUnderCursor_virtualFunctionCall_allOverrides();
void test_FollowSymbolUnderCursor_virtualFunctionCall_possibleOverrides1();
void test_FollowSymbolUnderCursor_virtualFunctionCall_possibleOverrides2();
void test_FollowSymbolUnderCursor_virtualFunctionCall_notOnQualified();
void test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDeclaration();
void test_FollowSymbolUnderCursor_virtualFunctionCall_notOnDefinition();
void test_FollowSymbolUnderCursor_virtualFunctionCall_notOnNonPointerNonReference();
void test_doxygen_comments_qt_style();
void test_doxygen_comments_qt_style_continuation();
......
......@@ -272,10 +272,11 @@ CppMacro::CppMacro(const Macro &macro)
// CppDeclarableElement
CppDeclarableElement::CppDeclarableElement(Symbol *declaration) : CppElement()
CppDeclarableElement::CppDeclarableElement(Symbol *declaration)
: CppElement()
, declaration(declaration)
, icon(Icons().iconForSymbol(declaration))
{
icon = Icons().iconForSymbol(declaration);
Overview overview;
overview.showArgumentNames = true;
overview.showReturnTypes = true;
......@@ -309,6 +310,11 @@ CppClass::CppClass(Symbol *declaration) : CppDeclarableElement(declaration)
tooltip = qualifiedName;
}
bool CppClass::operator==(const CppClass &other)
{
return this->declaration == other.declaration;
}
void CppClass::lookupBases(Symbol *declaration, const CPlusPlus::LookupContext &context)
{
typedef QPair<ClassOrNamespace *, CppClass *> Data;
......
......@@ -135,6 +135,7 @@ public:
explicit CppDeclarableElement(CPlusPlus::Symbol *declaration);
public:
CPlusPlus::Symbol *declaration;
QString name;
QString qualifiedName;
QString type;
......@@ -153,6 +154,8 @@ public:
CppClass();
explicit CppClass(CPlusPlus::Symbol *declaration);
bool operator==(const CppClass &other);
void lookupBases(CPlusPlus::Symbol *declaration, const CPlusPlus::LookupContext &context);
void lookupDerived(CPlusPlus::Symbol *declaration, const CPlusPlus::Snapshot &snapshot);
......
......@@ -34,7 +34,9 @@
#include <cplusplus/CppDocument.h>
#include <texteditor/basetexteditor.h>
#include <QTextCursor>
QT_BEGIN_NAMESPACE
class QTextCursor;
QT_END_NAMESPACE
namespace CppTools { class SymbolFinder; }
......@@ -42,32 +44,27 @@ namespace CppEditor {
namespace Internal {
class CPPEditorWidget;
class VirtualFunctionAssistProvider;
class FollowSymbolUnderCursor
{
public:
typedef TextEditor::BaseTextEditorWidget::Link Link;
// Ownership of widget and symbolFinder is *not* transferred.
FollowSymbolUnderCursor(CPPEditorWidget *widget, const QTextCursor &cursor, bool resolveTarget,
const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
CppTools::SymbolFinder *symbolFinder);
FollowSymbolUnderCursor(CPPEditorWidget *widget);
~FollowSymbolUnderCursor();
Link findLink();
Link findLink(const QTextCursor &cursor, bool resolveTarget,
const CPlusPlus::Snapshot &snapshot,
const CPlusPlus::Document::Ptr &documentFromSemanticInfo,
CppTools::SymbolFinder *symbolFinder, bool inNextSplit);
private:
Link attemptFuncDeclDef(const QTextCursor &cursor);
CPlusPlus::Symbol *findDefinition(CPlusPlus::Symbol *symbol,
const CPlusPlus::Snapshot &snapshot) const;
VirtualFunctionAssistProvider *virtualFunctionAssistProvider();
void setVirtualFunctionAssistProvider(VirtualFunctionAssistProvider *provider);
private:
CppEditor::Internal::CPPEditorWidget *m_widget;
const QTextCursor m_cursor;
const bool m_resolveTarget;
CPlusPlus::Snapshot m_snapshot;
CPlusPlus::Document::Ptr m_document; // from SemanticInfo, i.e. with AST
CppTools::SymbolFinder *m_symbolFinder;
CPPEditorWidget *m_widget;
VirtualFunctionAssistProvider *m_virtualFunctionAssistProvider;
};
} // namespace Internal
......
This diff is collapsed.
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CPPFOLLOWVIRTUALSYMBOLS_H
#define CPPFOLLOWVIRTUALSYMBOLS_H
#include <texteditor/codeassist/iassistprovider.h>
#include <cplusplus/CppDocument.h>
#include <cplusplus/Symbols.h>
namespace CppEditor {
namespace Internal {
class VirtualFunctionAssistProvider : public TextEditor::IAssistProvider
{
public:
VirtualFunctionAssistProvider();
virtual bool configure(CPlusPlus::Class *startClass, CPlusPlus::Function *function,
const CPlusPlus::Snapshot &snapshot, bool openInNextSplit);
CPlusPlus::Class *startClass() const { return m_startClass; }
CPlusPlus::Function *function() const { return m_function; }
CPlusPlus::Snapshot snapshot() const { return m_snapshot; }
bool openInNextSplit() const { return m_openInNextSplit; }
bool isAsynchronous() const;
bool supportsEditor(const Core::Id &editorId) const;
TextEditor::IAssistProcessor *createProcessor() const;
private:
CPlusPlus::Class *m_startClass;
CPlusPlus::Function *m_function;
CPlusPlus::Snapshot m_snapshot;
bool m_openInNextSplit;
};
class FunctionHelper
{
public:
static bool isVirtualFunction(CPlusPlus::Function *function,
const CPlusPlus::Snapshot &snapshot);
static bool isPureVirtualFunction(CPlusPlus::Function *function,
const CPlusPlus::Snapshot &snapshot);
static QList<CPlusPlus::Symbol *> overrides(CPlusPlus::Class *startClass,
CPlusPlus::Function *function, const CPlusPlus::Snapshot &snapshot);
};
} // namespace Internal
} // namespace CppEditor
#endif // CPPFOLLOWVIRTUALSYMBOLS_H
......@@ -1063,7 +1063,9 @@ void QmlJSTextEditorWidget::createToolBar(QmlJSEditor *editor)
editor->insertExtraToolBarWidget(TextEditor::BaseTextEditor::Left, m_outlineCombo);
}
TextEditor::BaseTextEditorWidget::Link QmlJSTextEditorWidget::findLinkAt(const QTextCursor &cursor, bool /*resolveTarget*/)
TextEditor::BaseTextEditorWidget::Link QmlJSTextEditorWidget::findLinkAt(const QTextCursor &cursor,
bool /*resolveTarget*/,
bool /*inNextSplit*/)
{
const SemanticInfo semanticInfo = m_semanticInfo;
if (! semanticInfo.isValid())
......
......@@ -161,7 +161,9 @@ protected:
void scrollContentsBy(int dx, int dy);
TextEditor::BaseTextEditor *createEditor();
void createToolBar(QmlJSEditor *editable);
TextEditor::BaseTextEditorWidget::Link findLinkAt(const QTextCursor &cursor, bool resolveTarget = true);
TextEditor::BaseTextEditorWidget::Link findLinkAt(const QTextCursor &cursor,
bool resolveTarget = true,
bool inNextSplit = false);
QString foldReplacementText(const QTextBlock &block) const;
private:
......
......@@ -112,7 +112,8 @@ static bool isValidFileNameChar(const QChar &c)
}
ProFileEditorWidget::Link ProFileEditorWidget::findLinkAt(const QTextCursor &cursor,
bool /* resolveTarget */)
bool /*resolveTarget*/,
bool /*inNextSplit*/)
{
Link link;
......
......@@ -72,7 +72,8 @@ public:
void unCommentSelection();
protected:
virtual Link findLinkAt(const QTextCursor &, bool resolveTarget = true);
virtual Link findLinkAt(const QTextCursor &, bool resolveTarget = true,
bool inNextSplit = false);
TextEditor::BaseTextEditor *createEditor();
void contextMenuEvent(QContextMenuEvent *);
......
......@@ -1047,16 +1047,16 @@ void BaseTextEditorWidget::unindent()
void BaseTextEditorWidget::openLinkUnderCursor()
{
Link symbolLink = findLinkAt(textCursor());
openLink(symbolLink, alwaysOpenLinksInNextSplit());
const bool openInNextSplit = alwaysOpenLinksInNextSplit();
Link symbolLink = findLinkAt(textCursor(), true, openInNextSplit);
openLink(symbolLink, openInNextSplit);
}
void BaseTextEditorWidget::openLinkUnderCursorInNextSplit()
{
Link symbolLink = findLinkAt(textCursor());
openLink(symbolLink, !alwaysOpenLinksInNextSplit());
const bool openInNextSplit = !alwaysOpenLinksInNextSplit();
Link symbolLink = findLinkAt(textCursor(), true, openInNextSplit);
openLink(symbolLink, openInNextSplit);
}
void BaseTextEditorWidget::abortAssist()
......@@ -4803,7 +4803,7 @@ void BaseTextEditorWidget::reindent(QTextDocument *doc, const QTextCursor &curso
d->m_indenter->reindent(doc, cursor, tabSettings());
}
BaseTextEditorWidget::Link BaseTextEditorWidget::findLinkAt(const QTextCursor &, bool)
BaseTextEditorWidget::Link BaseTextEditorWidget::findLinkAt(const QTextCursor &, bool, bool)
{
return Link();
}
......
......@@ -503,7 +503,8 @@ protected:
\a resolveTarget is set to true when the target of the link is relevant
(it isn't until the link is used).
*/
virtual Link findLinkAt(const QTextCursor &, bool resolveTarget = true);
virtual Link findLinkAt(const QTextCursor &, bool resolveTarget = true,
bool inNextSplit = false);
/*!
Reimplement this function if you want to customize the way a link is
......
......@@ -35,7 +35,8 @@ namespace TextEditor {
enum AssistKind
{
Completion,
QuickFix
QuickFix,
FollowSymbol
};
enum AssistReason
......
......@@ -547,9 +547,7 @@ bool GenericProposalWidget::eventFilter(QObject *o, QEvent *e)
if (fe->reason() == Qt::OtherFocusReason) {
// Qt/carbon workaround
// focus out is received before the key press event.
if (d->m_completionListView->currentIndex().isValid())
emit proposalItemActivated(d->m_model->proposalItem(
d->m_completionListView->currentIndex().row()));
activateCurrentProposalItem();
}
}
if (d->m_infoFrame)
......@@ -593,9 +591,7 @@ bool GenericProposalWidget::eventFilter(QObject *o, QEvent *e)
case Qt::Key_Return:
if (!useCarbonWorkaround()) {
abort();
if (d->m_completionListView->currentIndex().isValid())
emit proposalItemActivated(d->m_model->proposalItem(
d->m_completionListView->currentIndex().row()));
activateCurrentProposalItem();
}
return true;
......@@ -658,6 +654,16 @@ bool GenericProposalWidget::eventFilter(QObject *o, QEvent *e)
return false;
}
bool GenericProposalWidget::activateCurrentProposalItem()
{
if (d->m_completionListView->currentIndex().isValid()) {
const int currentRow = d->m_completionListView->currentIndex().row();
emit proposalItemActivated(d->m_model->proposalItem(currentRow));
return true;
}
return false;
}
#include "genericproposalwidget.moc"
} // TextEditor
......@@ -32,11 +32,13 @@
#include "iassistproposalwidget.h"
#include <texteditor/texteditor_global.h>
namespace TextEditor {
class GenericProposalWidgetPrivate;
class GenericProposalWidget : public IAssistProposalWidget
class TEXTEDITOR_EXPORT GenericProposalWidget : public IAssistProposalWidget
{
Q_OBJECT
friend class GenericProposalWidgetPrivate;
......@@ -69,6 +71,7 @@ private slots:
protected:
virtual bool eventFilter(QObject *o, QEvent *e);
bool activateCurrentProposalItem();
private:
GenericProposalWidgetPrivate *d;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment