File indexing completed on 2024-05-12 04:39:08

0001 /*
0002     SPDX-FileCopyrightText: 2009 David Nolden <david.nolden.kdevelop@art-master.de>
0003     SPDX-FileCopyrightText: 2014 Kevin Funk <kfunk@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "adaptsignatureaction.h"
0009 #include "codegenhelper.h"
0010 
0011 #include "../duchain/duchainutils.h"
0012 #include "../util/clangdebug.h"
0013 
0014 #include <language/assistant/renameaction.h>
0015 #include <language/codegen/documentchangeset.h>
0016 #include <language/duchain/duchain.h>
0017 #include <language/duchain/duchainlock.h>
0018 #include <language/duchain/duchainutils.h>
0019 #include <language/duchain/functiondefinition.h>
0020 
0021 #include <interfaces/icore.h>
0022 #include <interfaces/iuicontroller.h>
0023 #include <sublime/message.h>
0024 // KF
0025 #include <KLocalizedString>
0026 
0027 using namespace KDevelop;
0028 
0029 AdaptSignatureAction::AdaptSignatureAction(const DeclarationId& definitionId,
0030                                            const ReferencedTopDUContext& definitionContext,
0031                                            const Signature& oldSignature,
0032                                            const Signature& newSignature,
0033                                            bool editingDefinition,
0034                                            const QList<RenameAction*>& renameActions)
0035     : m_otherSideId(definitionId)
0036     , m_otherSideTopContext(definitionContext)
0037     , m_oldSignature(oldSignature)
0038     , m_newSignature(newSignature)
0039     , m_editingDefinition(editingDefinition)
0040     , m_renameActions(renameActions)
0041 {
0042 }
0043 
0044 AdaptSignatureAction::~AdaptSignatureAction()
0045 {
0046     qDeleteAll(m_renameActions);
0047 }
0048 
0049 QString AdaptSignatureAction::description() const
0050 {
0051     return m_editingDefinition ? i18n("Update declaration signature") : i18n("Update definition signature");
0052 }
0053 
0054 QString AdaptSignatureAction::toolTip() const
0055 {
0056     DUChainReadLocker lock;
0057     auto declaration = m_otherSideId.declaration(m_otherSideTopContext.data());
0058     if (!declaration) {
0059         return {};
0060     }
0061     KLocalizedString msg = m_editingDefinition
0062                          ? ki18n("Update declaration signature\nfrom: %1\nto: %2")
0063                          : ki18n("Update definition signature\nfrom: %1\nto: %2");
0064     msg = msg.subs(CodegenHelper::makeSignatureString(declaration, m_oldSignature, m_editingDefinition));
0065     msg = msg.subs(CodegenHelper::makeSignatureString(declaration, m_newSignature, !m_editingDefinition));
0066     return msg.toString();
0067 }
0068 
0069 void AdaptSignatureAction::execute()
0070 {
0071     ENSURE_CHAIN_NOT_LOCKED
0072     DUChainReadLocker lock;
0073     IndexedString url = m_otherSideTopContext->url();
0074     lock.unlock();
0075     m_otherSideTopContext = DUChain::self()->waitForUpdate(url, TopDUContext::AllDeclarationsContextsAndUses);
0076     if (!m_otherSideTopContext) {
0077         clangDebug() << "failed to update" << url.str();
0078         return;
0079     }
0080 
0081     lock.lock();
0082 
0083     Declaration* otherSide = m_otherSideId.declaration(m_otherSideTopContext.data());
0084     if (!otherSide) {
0085         clangDebug() << "could not find definition";
0086         return;
0087     }
0088     DUContext* functionContext = DUChainUtils::functionContext(otherSide);
0089     if (!functionContext) {
0090         clangDebug() << "no function context";
0091         return;
0092     }
0093     if (!functionContext || functionContext->type() != DUContext::Function) {
0094         clangDebug() << "no correct function context";
0095         return;
0096     }
0097 
0098     DocumentChangeSet changes;
0099     KTextEditor::Range parameterRange = ClangIntegration::DUChainUtils::functionSignatureRange(otherSide);
0100     QString newText = CodegenHelper::makeSignatureString(otherSide, m_newSignature, !m_editingDefinition);
0101     if (!m_editingDefinition) {
0102         // append a newline after the method signature in case the method definition follows
0103         newText += QLatin1Char('\n');
0104     }
0105 
0106     DocumentChange changeParameters(functionContext->url(), parameterRange, QString(), newText);
0107     lock.unlock();
0108     changeParameters.m_ignoreOldText = true;
0109     changes.addChange(changeParameters);
0110     changes.setReplacementPolicy(DocumentChangeSet::WarnOnFailedChange);
0111     DocumentChangeSet::ChangeResult result = changes.applyAllChanges();
0112     if (!result) {
0113         const QString messageText = i18n("Failed to apply changes: %1", result.m_failureReason);
0114         auto* message = new Sublime::Message(messageText, Sublime::Message::Error);
0115         ICore::self()->uiController()->postMessage(message);
0116     }
0117     emit executed(this);
0118 
0119     for (RenameAction* renAct : m_renameActions) {
0120         renAct->execute();
0121     }
0122 }
0123 
0124 #include "moc_adaptsignatureaction.cpp"