summaryrefslogtreecommitdiff
path: root/src/plugins/cppeditor/cppeditor.cpp
diff options
context:
space:
mode:
authorChristian Kamm <christian.d.kamm@nokia.com>2011-08-10 09:50:04 +0200
committerChristian Kamm <christian.d.kamm@nokia.com>2011-08-16 11:13:12 +0200
commit8f14bc0ea23495dfb1dae7aea1910e470281ee26 (patch)
tree9e0580da96ff5010d4c4b17c1ab67a709c917a31 /src/plugins/cppeditor/cppeditor.cpp
parent13c8f9eaaae4adf7d4dc92cc6cb1f0d5cd3995b0 (diff)
downloadqt-creator-8f14bc0ea23495dfb1dae7aea1910e470281ee26.tar.gz
C++: Synchronize function decl/def refactoring.
When editing a function declaration or definition the code model may realize the same changes have to be applied somewhere else. A refactoring marker will pop up that can be clicked to perform the changes. Alternatively, press enter to apply. Change-Id: I2299a2ecfb6a8f87d4853fc7cfa99486f890a1d3 Reviewed-on: http://codereview.qt.nokia.com/2909 Reviewed-by: Leandro T. C. Melo <leandro.melo@nokia.com>
Diffstat (limited to 'src/plugins/cppeditor/cppeditor.cpp')
-rw-r--r--src/plugins/cppeditor/cppeditor.cpp193
1 files changed, 120 insertions, 73 deletions
diff --git a/src/plugins/cppeditor/cppeditor.cpp b/src/plugins/cppeditor/cppeditor.cpp
index bc07e4ffbc..c15f1e04e7 100644
--- a/src/plugins/cppeditor/cppeditor.cpp
+++ b/src/plugins/cppeditor/cppeditor.cpp
@@ -67,6 +67,7 @@
#include <cpptools/cppcompletionassist.h>
#include <cpptools/cppqtstyleindenter.h>
#include <cpptools/cppcodestylesettings.h>
+#include <cpptools/cpprefactoringchanges.h>
#include <coreplugin/icore.h>
#include <coreplugin/actionmanager/actionmanager.h>
@@ -76,6 +77,7 @@
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/mimedatabase.h>
+#include <utils/qtcassert.h>
#include <utils/uncommentselection.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
@@ -84,6 +86,7 @@
#include <texteditor/fontsettings.h>
#include <texteditor/tabsettings.h>
#include <texteditor/texteditorconstants.h>
+#include <texteditor/refactoroverlay.h>
#include <texteditor/codeassist/basicproposalitemlistmodel.h>
#include <texteditor/codeassist/basicproposalitem.h>
#include <texteditor/codeassist/genericproposal.h>
@@ -111,7 +114,8 @@
enum {
UPDATE_OUTLINE_INTERVAL = 500,
- UPDATE_USES_INTERVAL = 500
+ UPDATE_USES_INTERVAL = 500,
+ UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL = 200
};
using namespace CPlusPlus;
@@ -464,6 +468,13 @@ CPPEditorWidget::CPPEditorWidget(QWidget *parent)
m_referencesRevision = 0;
m_referencesCursorPosition = 0;
connect(&m_referencesWatcher, SIGNAL(finished()), SLOT(markSymbolsNow()));
+
+ connect(this, SIGNAL(refactorMarkerClicked(TextEditor::RefactorMarker)),
+ this, SLOT(onRefactorMarkerClicked(TextEditor::RefactorMarker)));
+
+ m_declDefLinkFinder = new FunctionDeclDefLinkFinder(this);
+ connect(m_declDefLinkFinder, SIGNAL(foundLink(QSharedPointer<FunctionDeclDefLink>)),
+ this, SLOT(onFunctionDeclDefLinkFound(QSharedPointer<FunctionDeclDefLink>)));
}
CPPEditorWidget::~CPPEditorWidget()
@@ -533,6 +544,11 @@ void CPPEditorWidget::createToolBar(CPPEditor *editor)
m_updateUsesTimer->setInterval(UPDATE_USES_INTERVAL);
connect(m_updateUsesTimer, SIGNAL(timeout()), this, SLOT(updateUsesNow()));
+ m_updateFunctionDeclDefLinkTimer = new QTimer(this);
+ m_updateFunctionDeclDefLinkTimer->setSingleShot(true);
+ m_updateFunctionDeclDefLinkTimer->setInterval(UPDATE_FUNCTION_DECL_DEF_LINK_INTERVAL);
+ connect(m_updateFunctionDeclDefLinkTimer, SIGNAL(timeout()), this, SLOT(updateFunctionDeclDefLinkNow()));
+
connect(m_outlineCombo, SIGNAL(activated(int)), this, SLOT(jumpToOutlineElement(int)));
connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateOutlineIndex()));
connect(m_outlineCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateOutlineToolTip()));
@@ -540,6 +556,9 @@ void CPPEditorWidget::createToolBar(CPPEditor *editor)
connect(file(), SIGNAL(changed()), this, SLOT(updateFileName()));
+ // set up function declaration - definition link
+ connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateFunctionDeclDefLink()));
+ connect(this, SIGNAL(textChanged()), this, SLOT(updateFunctionDeclDefLink()));
// set up the semantic highlighter
connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateUses()));
@@ -1170,77 +1189,6 @@ static inline LookupItem skipForwardDeclarations(const QList<LookupItem> &resolv
return result;
}
-namespace {
-
-QList<Declaration *> findMatchingDeclaration(const LookupContext &context,
- Function *functionType)
-{
- QList<Declaration *> result;
-
- Scope *enclosingScope = functionType->enclosingScope();
- while (! (enclosingScope->isNamespace() || enclosingScope->isClass()))
- enclosingScope = enclosingScope->enclosingScope();
- Q_ASSERT(enclosingScope != 0);
-
- const Name *functionName = functionType->name();
- if (! functionName)
- return result; // anonymous function names are not valid c++
-
- ClassOrNamespace *binding = 0;
- const QualifiedNameId *qName = functionName->asQualifiedNameId();
- if (qName) {
- if (qName->base())
- binding = context.lookupType(qName->base(), enclosingScope);
- functionName = qName->name();
- }
-
- if (!binding) { // declaration for a global function
- binding = context.lookupType(enclosingScope);
-
- if (!binding)
- return result;
- }
-
- const Identifier *funcId = functionName->identifier();
- if (!funcId) // E.g. operator, which we might be able to handle in the future...
- return result;
-
- QList<Declaration *> good, better, best;
-
- foreach (Symbol *s, binding->symbols()) {
- Class *matchingClass = s->asClass();
- if (!matchingClass)
- continue;
-
- for (Symbol *s = matchingClass->find(funcId); s; s = s->next()) {
- if (! s->name())
- continue;
- else if (! funcId->isEqualTo(s->identifier()))
- continue;
- else if (! s->type()->isFunctionType())
- continue;
- else if (Declaration *decl = s->asDeclaration()) {
- if (Function *declFunTy = decl->type()->asFunctionType()) {
- if (functionType->isEqualTo(declFunTy))
- best.prepend(decl);
- else if (functionType->argumentCount() == declFunTy->argumentCount() && result.isEmpty())
- better.prepend(decl);
- else
- good.append(decl);
- }
- }
- }
- }
-
- result.append(best);
- result.append(better);
- result.append(good);
-
- return result;
-}
-
-} // end of anonymous namespace
-
CPPEditorWidget::Link CPPEditorWidget::attemptFuncDeclDef(const QTextCursor &cursor, const Document::Ptr &doc, Snapshot snapshot) const
{
snapshot.insert(doc);
@@ -1616,7 +1564,10 @@ bool CPPEditorWidget::event(QEvent *e)
{
switch (e->type()) {
case QEvent::ShortcutOverride:
- if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape && m_currentRenameSelection != NoCurrentRenameSelection) {
+ // handle escape manually if a rename or func decl/def link is active
+ if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape
+ && (m_currentRenameSelection != NoCurrentRenameSelection
+ || m_declDefLink)) {
e->accept();
return true;
}
@@ -1691,10 +1642,29 @@ void CPPEditorWidget::contextMenuEvent(QContextMenuEvent *e)
void CPPEditorWidget::keyPressEvent(QKeyEvent *e)
{
if (m_currentRenameSelection == NoCurrentRenameSelection) {
+ // key handling for linked function declarations/definitions
+ if (m_declDefLink && m_declDefLink->isMarkerVisible()) {
+ switch (e->key()) {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ applyDeclDefLinkChanges(/*jump tp change*/ e->modifiers() & Qt::ShiftModifier);
+ e->accept();
+ return;
+ case Qt::Key_Escape:
+ abortDeclDefLink();
+ e->accept();
+ return;
+ default:
+ break;
+ }
+ }
+
TextEditor::BaseTextEditorWidget::keyPressEvent(e);
return;
}
+ // key handling for renames
+
QTextCursor cursor = textCursor();
const QTextCursor::MoveMode moveMode =
(e->modifiers() & Qt::ShiftModifier) ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor;
@@ -1974,6 +1944,9 @@ void CPPEditorWidget::updateSemanticInfo(const SemanticInfo &semanticInfo)
}
m_lastSemanticInfo.forced = false; // clear the forced flag
+
+ // schedule a check for a decl/def link
+ updateFunctionDeclDefLink();
}
namespace {
@@ -2274,4 +2247,78 @@ TextEditor::IAssistInterface *CPPEditorWidget::createAssistInterface(
return 0;
}
+void CPPEditorWidget::onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker)
+{
+ if (marker.data.canConvert<FunctionDeclDefLink::Marker>())
+ applyDeclDefLinkChanges(true);
+}
+
+void CPPEditorWidget::updateFunctionDeclDefLink()
+{
+ const int pos = textCursor().selectionStart();
+
+ // if there's already a link, abort it if the cursor is outside
+ if (m_declDefLink
+ && (pos < m_declDefLink->linkSelection.selectionStart()
+ || pos > m_declDefLink->linkSelection.selectionEnd())) {
+ abortDeclDefLink();
+ return;
+ }
+
+ // don't start a new scan if there's one active and the cursor is already in the scanned area
+ const QTextCursor scannedSelection = m_declDefLinkFinder->scannedSelection();
+ if (!scannedSelection.isNull()
+ && scannedSelection.selectionStart() <= pos
+ && scannedSelection.selectionEnd() >= pos) {
+ return;
+ }
+
+ m_updateFunctionDeclDefLinkTimer->start();
+}
+
+void CPPEditorWidget::updateFunctionDeclDefLinkNow()
+{
+ if (Core::EditorManager::instance()->currentEditor() != editor())
+ return;
+ if (m_declDefLink) {
+ // update the change marker
+ const Utils::ChangeSet changes = m_declDefLink->changes(m_lastSemanticInfo.snapshot);
+ if (changes.isEmpty())
+ m_declDefLink->hideMarker(this);
+ else
+ m_declDefLink->showMarker(this);
+ return;
+ }
+ if (!m_lastSemanticInfo.doc || isOutdated())
+ return;
+
+ Snapshot snapshot = CppModelManagerInterface::instance()->snapshot();
+ snapshot.insert(m_lastSemanticInfo.doc);
+
+ m_declDefLinkFinder->startFindLinkAt(textCursor(), m_lastSemanticInfo.doc, snapshot);
+}
+
+void CPPEditorWidget::onFunctionDeclDefLinkFound(QSharedPointer<FunctionDeclDefLink> link)
+{
+ abortDeclDefLink();
+ m_declDefLink = link;
+}
+
+void CPPEditorWidget::applyDeclDefLinkChanges(bool jumpToMatch)
+{
+ if (!m_declDefLink)
+ return;
+ m_declDefLink->apply(this, jumpToMatch);
+ m_declDefLink.clear();
+ updateFunctionDeclDefLink();
+}
+
+void CPPEditorWidget::abortDeclDefLink()
+{
+ if (!m_declDefLink)
+ return;
+ m_declDefLink->hideMarker(this);
+ m_declDefLink.clear();
+}
+
#include "cppeditor.moc"