mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-27 20:32:54 +00:00
193 lines
6.7 KiB
C++
193 lines
6.7 KiB
C++
/*
|
|
Copyright 2009 David Nolden <david.nolden.kdevelop@art-master.de>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License version 2 as published by the Free Software Foundation.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "adaptsignatureaction.h"
|
|
|
|
#include <language/assistant/renameaction.h>
|
|
#include <language/codegen/documentchangeset.h>
|
|
#include <language/duchain/types/arraytype.h>
|
|
#include <language/duchain/duchain.h>
|
|
#include <language/duchain/duchainlock.h>
|
|
#include <language/duchain/duchainutils.h>
|
|
#include <KLocalizedString>
|
|
#include <KMessageBox>
|
|
|
|
#include "languages/cpp/cppduchain/cppduchain.h"
|
|
|
|
using namespace KDevelop;
|
|
using namespace Cpp;
|
|
|
|
QString makeSignatureString(const Signature& signature, DUContext* visibilityFrom) {
|
|
QString ret;
|
|
int pos = 0;
|
|
foreach(const ParameterItem& item, signature.parameters) {
|
|
if(!ret.isEmpty())
|
|
ret += ", ";
|
|
|
|
///TODO: merge common code with helpers.cpp::createArgumentList
|
|
AbstractType::Ptr type = item.first.abstractType();
|
|
|
|
QString arrayAppendix;
|
|
ArrayType::Ptr arrayType;
|
|
while ((arrayType = type.cast<ArrayType>())) {
|
|
type = arrayType->elementType();
|
|
//note: we have to prepend since we iterate from outside, i.e. from right to left.
|
|
if (arrayType->dimension()) {
|
|
arrayAppendix.prepend(QString("[%1]").arg(arrayType->dimension()));
|
|
} else {
|
|
// dimensionless
|
|
arrayAppendix.prepend("[]");
|
|
}
|
|
}
|
|
ret += Cpp::simplifiedTypeString(type, visibilityFrom);
|
|
|
|
if(!item.second.isEmpty())
|
|
ret += " " + item.second;
|
|
|
|
ret += arrayAppendix;
|
|
|
|
if (signature.defaultParams.size() > pos && !signature.defaultParams[pos].isEmpty())
|
|
ret += " = " + signature.defaultParams[pos];
|
|
|
|
++pos;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
AdaptSignatureAction::AdaptSignatureAction(
|
|
const DeclarationId& definitionId,
|
|
ReferencedTopDUContext definitionContext,
|
|
const Signature& oldSignature,
|
|
const Signature& newSignature,
|
|
bool editingDefinition,
|
|
QList<RenameAction*> renameActions
|
|
)
|
|
: m_otherSideId(definitionId),
|
|
m_otherSideTopContext(definitionContext),
|
|
m_oldSignature(oldSignature),
|
|
m_newSignature(newSignature),
|
|
m_editingDefinition(editingDefinition),
|
|
m_renameActions(renameActions) {
|
|
}
|
|
|
|
AdaptSignatureAction::~AdaptSignatureAction()
|
|
{
|
|
qDeleteAll(m_renameActions);
|
|
}
|
|
|
|
QString AdaptSignatureAction::description() const {
|
|
return m_editingDefinition ? i18n("Update declaration signature") : i18n("Update definition signature");
|
|
}
|
|
|
|
QString AdaptSignatureAction::toolTip() const {
|
|
DUChainReadLocker lock;
|
|
return i18n("Update %1\nfrom: %2(%3)%4\nto: %2(%5)%6",
|
|
m_editingDefinition ? i18n("declaration") : i18n("definition"),
|
|
m_otherSideId.qualifiedIdentifier().toString(),
|
|
makeSignatureString(m_oldSignature, m_otherSideTopContext.data()),
|
|
m_oldSignature.isConst ? " const" : "",
|
|
makeSignatureString(m_newSignature, m_otherSideTopContext.data()),
|
|
m_newSignature.isConst ? " const" : "");
|
|
}
|
|
|
|
void AdaptSignatureAction::execute() {
|
|
DUChainReadLocker lock;
|
|
IndexedString url = m_otherSideTopContext->url();
|
|
lock.unlock();
|
|
m_otherSideTopContext = DUChain::self()->waitForUpdate(url, TopDUContext::AllDeclarationsContextsAndUses);
|
|
if(!m_otherSideTopContext) {
|
|
kDebug() << "failed to update" << url.str();
|
|
return;
|
|
}
|
|
|
|
lock.lock();
|
|
|
|
Declaration* otherSide = m_otherSideId.getDeclaration(m_otherSideTopContext.data());
|
|
if(!otherSide) {
|
|
kDebug() << "could not find definition";
|
|
return;
|
|
}
|
|
|
|
DUContext* functionContext = DUChainUtils::getFunctionContext(otherSide);
|
|
if(!functionContext) {
|
|
kDebug() << "no function context";
|
|
return;
|
|
}
|
|
|
|
if(!functionContext || functionContext->type() != DUContext::Function) {
|
|
kDebug() << "no correct function context";
|
|
return;
|
|
}
|
|
|
|
DocumentChangeSet changes;
|
|
DocumentChange changeParameters(functionContext->url(), functionContext->rangeInCurrentRevision(), QString(), makeSignatureString(m_newSignature, m_otherSideTopContext.data()));
|
|
changeParameters.m_ignoreOldText = true;
|
|
changes.addChange( changeParameters );
|
|
CodeRepresentation::Ptr document = createCodeRepresentation(functionContext->url());
|
|
const int l = functionContext->range().start.line;
|
|
const QString line = document->line(l);
|
|
if (m_oldSignature.isConst != m_newSignature.isConst) {
|
|
///TODO: also use code representation here
|
|
QRegExp pattern( QLatin1String("\\)\\s*") );
|
|
RangeInRevision range = functionContext->range();
|
|
// go after closing paren
|
|
int i = line.indexOf(pattern, range.end.column);
|
|
if (i != -1) {
|
|
range.start.column = i;
|
|
// we replace the full regexp match
|
|
QString oldText = pattern.cap();
|
|
range.end.column = i + oldText.length();
|
|
// by the trimmed version (whitespaces are added below as neede)
|
|
QString newText = pattern.cap().trimmed();
|
|
|
|
if (m_oldSignature.isConst) {
|
|
// remove const token
|
|
oldText += "const";
|
|
range.end.column += 5;
|
|
} else {
|
|
// add it
|
|
newText += " const";
|
|
}
|
|
DocumentChange changeConstness(functionContext->url(), range.castToSimpleRange(), oldText, newText);
|
|
changes.addChange(changeConstness);
|
|
}
|
|
}
|
|
if (m_oldSignature.returnType != m_newSignature.returnType) {
|
|
QRegExp exe( QString("^(\\s*)(.+)\\s+(?:\\w+::)*\\b%1\\s*\\(").arg(otherSide->identifier().toString()), Qt::CaseSensitive, QRegExp::RegExp2 );
|
|
int pos = exe.indexIn(line);
|
|
if (pos != -1) {
|
|
QString oldText = exe.cap(2);
|
|
SimpleRange range = SimpleRange(l, exe.cap(1).length(), l, exe.cap(1).length() + oldText.length());
|
|
QString newText = Cpp::simplifiedTypeString(m_newSignature.returnType.abstractType(), functionContext->parentContext());
|
|
DocumentChange changeRetType(functionContext->url(), range, oldText, newText);
|
|
changes.addChange(changeRetType);
|
|
}
|
|
}
|
|
changes.setReplacementPolicy(DocumentChangeSet::WarnOnFailedChange);
|
|
DocumentChangeSet::ChangeResult result = changes.applyAllChanges();
|
|
if(!result) {
|
|
KMessageBox::error(0, i18n("Failed to apply changes: %1", result.m_failureReason));
|
|
}
|
|
|
|
emit executed(this);
|
|
|
|
foreach(RenameAction *renAct, m_renameActions)
|
|
renAct->execute();
|
|
}
|
|
|
|
#include "moc_adaptsignatureaction.cpp"
|