diff --git a/src/plugins/cppeditor/CMakeLists.txt b/src/plugins/cppeditor/CMakeLists.txt index 49fe02c17e7..66e25f08feb 100644 --- a/src/plugins/cppeditor/CMakeLists.txt +++ b/src/plugins/cppeditor/CMakeLists.txt @@ -48,6 +48,7 @@ add_qtc_plugin(CppEditor cppfindreferences.cpp cppfindreferences.h cppfollowsymbolundercursor.cpp cppfollowsymbolundercursor.h cppfunctiondecldeflink.cpp cppfunctiondecldeflink.h + cppfunctionparamrenaminghandler.cpp cppfunctionparamrenaminghandler.h cpphighlighter.cpp cpphighlighter.h cppincludehierarchy.cpp cppincludehierarchy.h cppincludesfilter.cpp cppincludesfilter.h diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index 45a7901817a..2e8581a50c0 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -108,6 +108,8 @@ QtcPlugin { "cppfollowsymbolundercursor.h", "cppfunctiondecldeflink.cpp", "cppfunctiondecldeflink.h", + "cppfunctionparamrenaminghandler.cpp", + "cppfunctionparamrenaminghandler.h", "cpphighlighter.cpp", "cpphighlighter.h", "cppincludehierarchy.cpp", @@ -226,7 +228,7 @@ QtcPlugin { "symbolsfindfilter.h", "typehierarchybuilder.cpp", "typehierarchybuilder.h", - "wrappablelineedit.cpp", // FIXME: Is this used? + "wrappablelineedit.cpp", "wrappablelineedit.h", ] diff --git a/src/plugins/cppeditor/cppeditorwidget.cpp b/src/plugins/cppeditor/cppeditorwidget.cpp index dd49bbec90b..aa112e0b48f 100644 --- a/src/plugins/cppeditor/cppeditorwidget.cpp +++ b/src/plugins/cppeditor/cppeditorwidget.cpp @@ -11,13 +11,13 @@ #include "cppeditorplugin.h" #include "cppeditortr.h" #include "cppfunctiondecldeflink.h" +#include "cppfunctionparamrenaminghandler.h" #include "cpplocalrenaming.h" #include "cppmodelmanager.h" #include "cpppreprocessordialog.h" #include "cppquickfixassistant.h" #include "cppselectionchanger.h" #include "cppsemanticinfo.h" -#include "cpptoolssettings.h" #include "cppuseselectionsupdater.h" #include "doxygengenerator.h" @@ -396,6 +396,7 @@ public: QToolButton *m_preprocessorButton = nullptr; CppLocalRenaming m_localRenaming; + CppFunctionParamRenamingHandler m_paramRenamingHandler; CppUseSelectionsUpdater m_useSelectionsUpdater; CppSelectionChanger m_cppSelectionChanger; bool inTestMode = false; @@ -405,6 +406,7 @@ CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q) : m_cppEditorDocument(qobject_cast(q->textDocument())) , m_declDefLinkFinder(new FunctionDeclDefLinkFinder(q)) , m_localRenaming(q) + , m_paramRenamingHandler(*q, m_localRenaming) , m_useSelectionsUpdater(q) , m_cppSelectionChanger() {} diff --git a/src/plugins/cppeditor/cppfunctionparamrenaminghandler.cpp b/src/plugins/cppeditor/cppfunctionparamrenaminghandler.cpp new file mode 100644 index 00000000000..092e216b2d4 --- /dev/null +++ b/src/plugins/cppeditor/cppfunctionparamrenaminghandler.cpp @@ -0,0 +1,112 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "cppfunctionparamrenaminghandler.h" + +#include "cppeditorwidget.h" +#include "cpplocalrenaming.h" +#include "cppfunctiondecldeflink.h" + +#include +#include +#include + +#include + +using namespace CPlusPlus; + +namespace CppEditor::Internal { + +using DeclDefLinkPtr = QSharedPointer; + +class CppFunctionParamRenamingHandler::Private +{ +public: + Private(CppEditorWidget &editorWidget, CppLocalRenaming &localRenaming); + + void handleRenamingStarted(); + void handleRenamingFinished(); + void handleLinkFound(const DeclDefLinkPtr &link); + void findLink(FunctionDefinitionAST &func, const SemanticInfo &semanticInfo); + + CppEditorWidget &editorWidget; + CppLocalRenaming &localRenaming; + std::unique_ptr linkFinder; + DeclDefLinkPtr link; +}; + +CppFunctionParamRenamingHandler::CppFunctionParamRenamingHandler( + CppEditorWidget &editorWidget, CppLocalRenaming &localRenaming) + : d(new Private(editorWidget, localRenaming)) {} + +CppFunctionParamRenamingHandler::~CppFunctionParamRenamingHandler() { delete d; } + +CppFunctionParamRenamingHandler::Private::Private( + CppEditorWidget &editorWidget, CppLocalRenaming &localRenaming) + : editorWidget(editorWidget), localRenaming(localRenaming) +{ + QObject::connect(&localRenaming, &CppLocalRenaming::started, + &editorWidget, [this] { handleRenamingStarted(); }); + QObject::connect(&localRenaming, &CppLocalRenaming::finished, + &editorWidget, [this] { handleRenamingFinished(); }); +} + +void CppFunctionParamRenamingHandler::Private::handleRenamingStarted() +{ + linkFinder.reset(); + link.clear(); + + // Are we currently on the function signature? In this case, the normal decl/def link + // mechanism kicks in and we don't have to do anything. + if (editorWidget.declDefLink()) + return; + + // If we find a surrounding function definition, start up the decl/def link finder. + const SemanticInfo semanticInfo = editorWidget.semanticInfo(); + if (!semanticInfo.doc || !semanticInfo.doc->translationUnit()) + return; + const QList astPath = ASTPath(semanticInfo.doc)(editorWidget.textCursor()); + for (auto it = astPath.rbegin(); it != astPath.rend(); ++it) { + if (const auto func = (*it)->asFunctionDefinition()) { + findLink(*func, semanticInfo); + return; + } + } +} + +void CppFunctionParamRenamingHandler::Private::handleRenamingFinished() +{ + if (link) { + link->apply(&editorWidget, false); + link.clear(); + } +} + +void CppFunctionParamRenamingHandler::Private::handleLinkFound(const DeclDefLinkPtr &link) +{ + if (localRenaming.isActive()) + this->link = link; + linkFinder.reset(); +} + +void CppFunctionParamRenamingHandler::Private::findLink(FunctionDefinitionAST &func, + const SemanticInfo &semanticInfo) +{ + if (!func.declarator) + return; + + // The finder needs a cursor that points to the signature, so provide one. + QTextDocument * const doc = editorWidget.textDocument()->document(); + const int pos = semanticInfo.doc->translationUnit()->getTokenEndPositionInDocument( + func.declarator->firstToken(), doc); + QTextCursor cursor(doc); + cursor.setPosition(pos); + linkFinder.reset(new FunctionDeclDefLinkFinder); + QObject::connect(linkFinder.get(), &FunctionDeclDefLinkFinder::foundLink, + &editorWidget, [this](const DeclDefLinkPtr &link) { + handleLinkFound(link); + }); + linkFinder->startFindLinkAt(cursor, semanticInfo.doc, semanticInfo.snapshot); +} + +} // namespace CppEditor::Internal diff --git a/src/plugins/cppeditor/cppfunctionparamrenaminghandler.h b/src/plugins/cppeditor/cppfunctionparamrenaminghandler.h new file mode 100644 index 00000000000..e923855ca68 --- /dev/null +++ b/src/plugins/cppeditor/cppfunctionparamrenaminghandler.h @@ -0,0 +1,25 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +namespace CppEditor { +class CppEditorWidget; + +namespace Internal { +class CppLocalRenaming; + +// Watches local renamings and adapts the declaration if a function parameter was renamed. +class CppFunctionParamRenamingHandler +{ +public: + CppFunctionParamRenamingHandler(CppEditorWidget &editorWidget, CppLocalRenaming &localRenaming); + ~CppFunctionParamRenamingHandler(); + +private: + class Private; + Private * const d; +}; + +} // namespace Internal +} // namespace CppEditor diff --git a/src/plugins/cppeditor/cpplocalrenaming.cpp b/src/plugins/cppeditor/cpplocalrenaming.cpp index f23b9d80a67..5bad16a0b69 100644 --- a/src/plugins/cppeditor/cpplocalrenaming.cpp +++ b/src/plugins/cppeditor/cpplocalrenaming.cpp @@ -62,6 +62,7 @@ bool CppLocalRenaming::start() updateRenamingSelectionFormat(textCharFormat(TextEditor::C_OCCURRENCES_RENAME)); m_firstRenameChangeExpected = true; updateEditorWidgetWithSelections(); + emit started(); return true; } diff --git a/src/plugins/cppeditor/cpplocalrenaming.h b/src/plugins/cppeditor/cpplocalrenaming.h index 082d4648a8c..56ff1530441 100644 --- a/src/plugins/cppeditor/cpplocalrenaming.h +++ b/src/plugins/cppeditor/cpplocalrenaming.h @@ -41,6 +41,7 @@ public: bool isSameSelection(int cursorPosition) const; signals: + void started(); void finished(); void processKeyPressNormally(QKeyEvent *e);