2010-07-08 16:40:46 +02:00
|
|
|
/**************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
2011-01-11 16:28:15 +01:00
|
|
|
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
2010-07-08 16:40:46 +02:00
|
|
|
**
|
2011-04-13 08:42:33 +02:00
|
|
|
** Contact: Nokia Corporation (info@qt.nokia.com)
|
2010-07-08 16:40:46 +02:00
|
|
|
**
|
|
|
|
|
**
|
|
|
|
|
** GNU Lesser General Public License Usage
|
|
|
|
|
**
|
2011-04-13 08:42:33 +02:00
|
|
|
** 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.
|
2010-07-08 16:40:46 +02:00
|
|
|
**
|
2010-12-17 16:01:08 +01:00
|
|
|
** In addition, as a special exception, Nokia gives you certain additional
|
2011-04-13 08:42:33 +02:00
|
|
|
** rights. These rights are described in the Nokia Qt LGPL Exception
|
2010-12-17 16:01:08 +01:00
|
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
|
|
|
**
|
2011-04-13 08:42:33 +02:00
|
|
|
** Other Usage
|
|
|
|
|
**
|
|
|
|
|
** Alternatively, this file may be used in accordance with the terms and
|
|
|
|
|
** conditions contained in a signed written agreement between you and Nokia.
|
|
|
|
|
**
|
2010-12-17 16:01:08 +01:00
|
|
|
** If you have questions regarding the use of this file, please contact
|
2011-05-06 15:05:37 +02:00
|
|
|
** Nokia at info@qt.nokia.com.
|
2010-07-08 16:40:46 +02:00
|
|
|
**
|
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
2010-09-02 15:17:57 +02:00
|
|
|
#include "cppinsertdecldef.h"
|
2011-04-15 16:19:23 +02:00
|
|
|
#include "cppquickfixassistant.h"
|
2010-07-08 16:40:46 +02:00
|
|
|
|
2010-10-06 15:49:59 +02:00
|
|
|
#include <CPlusPlus.h>
|
2010-07-08 16:40:46 +02:00
|
|
|
#include <cplusplus/ASTPath.h>
|
2010-09-30 12:09:38 +02:00
|
|
|
#include <cplusplus/CppRewriter.h>
|
2010-07-08 16:40:46 +02:00
|
|
|
#include <cplusplus/LookupContext.h>
|
|
|
|
|
#include <cplusplus/Overview.h>
|
2010-09-30 14:00:43 +02:00
|
|
|
#include <cpptools/insertionpointlocator.h>
|
2010-11-01 17:04:48 +01:00
|
|
|
#include <cpptools/cpprefactoringchanges.h>
|
2010-07-08 16:40:46 +02:00
|
|
|
|
|
|
|
|
#include <QtCore/QCoreApplication>
|
2010-10-06 15:49:59 +02:00
|
|
|
#include <QtCore/QDir>
|
2010-07-08 16:40:46 +02:00
|
|
|
|
|
|
|
|
using namespace CPlusPlus;
|
2010-07-26 13:06:33 +02:00
|
|
|
using namespace CppEditor;
|
2010-07-08 16:40:46 +02:00
|
|
|
using namespace CppEditor::Internal;
|
|
|
|
|
using namespace CppTools;
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
2010-09-27 18:01:04 +02:00
|
|
|
class InsertDeclOperation: public CppQuickFixOperation
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
public:
|
2011-04-15 16:19:23 +02:00
|
|
|
InsertDeclOperation(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface,
|
|
|
|
|
int priority,
|
2010-09-27 18:01:04 +02:00
|
|
|
const QString &targetFileName, const Class *targetSymbol,
|
|
|
|
|
InsertionPointLocator::AccessSpec xsSpec,
|
|
|
|
|
const QString &decl)
|
2011-04-15 16:19:23 +02:00
|
|
|
: CppQuickFixOperation(interface, priority)
|
2010-07-26 13:06:33 +02:00
|
|
|
, m_targetFileName(targetFileName)
|
2010-07-27 15:29:16 +02:00
|
|
|
, m_targetSymbol(targetSymbol)
|
2010-07-30 14:55:11 +02:00
|
|
|
, m_xsSpec(xsSpec)
|
2010-07-26 13:06:33 +02:00
|
|
|
, m_decl(decl)
|
|
|
|
|
{
|
2010-07-30 14:55:11 +02:00
|
|
|
QString type;
|
|
|
|
|
switch (xsSpec) {
|
|
|
|
|
case InsertionPointLocator::Public: type = QLatin1String("public"); break;
|
|
|
|
|
case InsertionPointLocator::Protected: type = QLatin1String("protected"); break;
|
|
|
|
|
case InsertionPointLocator::Private: type = QLatin1String("private"); break;
|
|
|
|
|
case InsertionPointLocator::PublicSlot: type = QLatin1String("public slot"); break;
|
|
|
|
|
case InsertionPointLocator::ProtectedSlot: type = QLatin1String("protected slot"); break;
|
|
|
|
|
case InsertionPointLocator::PrivateSlot: type = QLatin1String("private slot"); break;
|
|
|
|
|
default: break;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-05 09:44:33 +02:00
|
|
|
setDescription(QCoreApplication::translate("CppEditor::InsertDeclOperation",
|
2010-10-06 16:33:49 +02:00
|
|
|
"Add %1 Declaration").arg(type));
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
2010-07-08 16:40:46 +02:00
|
|
|
|
2011-08-17 11:35:57 +02:00
|
|
|
void performChanges(const CppRefactoringFilePtr &,
|
|
|
|
|
const CppRefactoringChanges &refactoring)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
2010-09-30 12:09:38 +02:00
|
|
|
InsertionPointLocator locator(refactoring);
|
2010-09-27 18:01:04 +02:00
|
|
|
const InsertionLocation loc = locator.methodDeclarationInClass(
|
|
|
|
|
m_targetFileName, m_targetSymbol, m_xsSpec);
|
2010-07-29 14:59:38 +02:00
|
|
|
Q_ASSERT(loc.isValid());
|
2010-07-26 13:06:33 +02:00
|
|
|
|
2011-08-17 11:35:57 +02:00
|
|
|
CppRefactoringFilePtr targetFile = refactoring.file(m_targetFileName);
|
|
|
|
|
int targetPosition1 = targetFile->position(loc.line(), loc.column());
|
|
|
|
|
int targetPosition2 = qMax(0, targetFile->position(loc.line(), 1) - 1);
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
Utils::ChangeSet target;
|
2010-07-27 15:29:16 +02:00
|
|
|
target.insert(targetPosition1, loc.prefix() + m_decl);
|
2011-08-17 11:35:57 +02:00
|
|
|
targetFile->setChangeSet(target);
|
|
|
|
|
targetFile->appendIndentRange(Utils::ChangeSet::Range(targetPosition2, targetPosition1));
|
|
|
|
|
targetFile->setOpenEditor(true, targetPosition1);
|
|
|
|
|
targetFile->apply();
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
QString m_targetFileName;
|
2010-07-27 15:29:16 +02:00
|
|
|
const Class *m_targetSymbol;
|
2010-07-30 14:55:11 +02:00
|
|
|
InsertionPointLocator::AccessSpec m_xsSpec;
|
2010-07-26 13:06:33 +02:00
|
|
|
QString m_decl;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // anonymous namespace
|
2010-07-08 16:40:46 +02:00
|
|
|
|
2011-04-15 16:19:23 +02:00
|
|
|
QList<CppQuickFixOperation::Ptr> DeclFromDef::match(
|
|
|
|
|
const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface)
|
2010-07-08 16:40:46 +02:00
|
|
|
{
|
2011-04-15 16:19:23 +02:00
|
|
|
const QList<AST *> &path = interface->path();
|
2011-08-17 11:35:57 +02:00
|
|
|
CppRefactoringFilePtr file = interface->currentFile();
|
2010-07-08 16:40:46 +02:00
|
|
|
|
|
|
|
|
FunctionDefinitionAST *funDef = 0;
|
|
|
|
|
int idx = 0;
|
|
|
|
|
for (; idx < path.size(); ++idx) {
|
|
|
|
|
AST *node = path.at(idx);
|
2010-09-22 16:42:49 +02:00
|
|
|
if (idx > 1) {
|
|
|
|
|
if (DeclaratorIdAST *declId = node->asDeclaratorId()) {
|
2011-08-17 11:35:57 +02:00
|
|
|
if (file->isCursorOn(declId)) {
|
2010-09-22 16:42:49 +02:00
|
|
|
if (FunctionDefinitionAST *candidate = path.at(idx - 2)->asFunctionDefinition()) {
|
|
|
|
|
if (funDef) {
|
|
|
|
|
return noResult();
|
|
|
|
|
} else {
|
|
|
|
|
funDef = candidate;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (node->asClassSpecifier()) {
|
2010-07-26 13:06:33 +02:00
|
|
|
return noResult();
|
2010-07-13 14:36:14 +02:00
|
|
|
}
|
2010-07-08 16:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!funDef || !funDef->symbol)
|
2010-07-26 13:06:33 +02:00
|
|
|
return noResult();
|
2010-07-08 16:40:46 +02:00
|
|
|
|
|
|
|
|
Function *method = funDef->symbol;
|
|
|
|
|
|
2010-10-06 15:49:59 +02:00
|
|
|
Scope *enclosingScope = method->enclosingScope();
|
|
|
|
|
while (! (enclosingScope->isNamespace() || enclosingScope->isClass()))
|
|
|
|
|
enclosingScope = enclosingScope->enclosingScope();
|
|
|
|
|
Q_ASSERT(enclosingScope != 0);
|
|
|
|
|
|
|
|
|
|
const Name *functionName = method->name();
|
|
|
|
|
if (! functionName)
|
|
|
|
|
return noResult(); // warn, anonymous function names are not valid c++
|
|
|
|
|
|
|
|
|
|
if (! functionName->isQualifiedNameId())
|
|
|
|
|
return noResult(); // warn, trying to add a declaration for a global function
|
|
|
|
|
|
|
|
|
|
const QualifiedNameId *q = functionName->asQualifiedNameId();
|
|
|
|
|
if (!q->base())
|
|
|
|
|
return noResult();
|
|
|
|
|
|
2011-04-15 16:19:23 +02:00
|
|
|
if (ClassOrNamespace *binding = interface->context().lookupType(q->base(), enclosingScope)) {
|
2010-10-06 15:49:59 +02:00
|
|
|
foreach (Symbol *s, binding->symbols()) {
|
|
|
|
|
if (Class *matchingClass = s->asClass()) {
|
|
|
|
|
for (Symbol *s = matchingClass->find(q->identifier()); s; s = s->next()) {
|
|
|
|
|
if (! s->name())
|
|
|
|
|
continue;
|
|
|
|
|
else if (! q->identifier()->isEqualTo(s->identifier()))
|
|
|
|
|
continue;
|
|
|
|
|
else if (! s->type()->isFunctionType())
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (s->type().isEqualTo(method->type()))
|
|
|
|
|
return noResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// a good candidate
|
|
|
|
|
|
|
|
|
|
const QString fn = QString::fromUtf8(matchingClass->fileName(),
|
|
|
|
|
matchingClass->fileNameLength());
|
2011-04-15 16:19:23 +02:00
|
|
|
const QString decl = generateDeclaration(interface,
|
2010-07-30 14:55:11 +02:00
|
|
|
method,
|
2010-10-06 15:49:59 +02:00
|
|
|
binding);
|
|
|
|
|
return singleResult(
|
2011-04-15 16:19:23 +02:00
|
|
|
new InsertDeclOperation(interface, idx, fn, matchingClass,
|
2010-10-06 15:49:59 +02:00
|
|
|
InsertionPointLocator::Public,
|
|
|
|
|
decl));
|
|
|
|
|
}
|
2010-07-08 16:40:46 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-07-26 13:06:33 +02:00
|
|
|
return noResult();
|
2010-07-08 16:40:46 +02:00
|
|
|
}
|
|
|
|
|
|
2011-04-15 16:19:23 +02:00
|
|
|
QString DeclFromDef::generateDeclaration(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &,
|
2010-07-26 13:06:33 +02:00
|
|
|
Function *method,
|
|
|
|
|
ClassOrNamespace *targetBinding)
|
2010-07-08 16:40:46 +02:00
|
|
|
{
|
2010-07-29 15:16:43 +02:00
|
|
|
Q_UNUSED(targetBinding);
|
|
|
|
|
|
2010-07-08 16:40:46 +02:00
|
|
|
Overview oo;
|
2010-07-29 15:16:43 +02:00
|
|
|
oo.setShowFunctionSignatures(true);
|
|
|
|
|
oo.setShowReturnTypes(true);
|
|
|
|
|
oo.setShowArgumentNames(true);
|
2010-07-08 16:40:46 +02:00
|
|
|
|
2010-07-29 15:16:43 +02:00
|
|
|
QString decl;
|
2010-08-26 12:23:09 +02:00
|
|
|
decl += oo(method->type(), method->unqualifiedName());
|
2010-07-29 15:16:43 +02:00
|
|
|
decl += QLatin1String(";\n");
|
2010-07-08 16:40:46 +02:00
|
|
|
|
|
|
|
|
return decl;
|
|
|
|
|
}
|
2010-09-27 18:01:04 +02:00
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
2010-09-30 12:09:38 +02:00
|
|
|
class InsertDefOperation: public CppQuickFixOperation
|
2010-09-27 18:01:04 +02:00
|
|
|
{
|
2010-09-30 12:09:38 +02:00
|
|
|
public:
|
2011-04-15 16:19:23 +02:00
|
|
|
InsertDefOperation(const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface, int priority,
|
2010-09-30 12:09:38 +02:00
|
|
|
Declaration *decl, const InsertionLocation &loc)
|
2011-04-15 16:19:23 +02:00
|
|
|
: CppQuickFixOperation(interface, priority)
|
2010-09-30 12:09:38 +02:00
|
|
|
, m_decl(decl)
|
|
|
|
|
, m_loc(loc)
|
|
|
|
|
{
|
2010-10-06 15:49:59 +02:00
|
|
|
const QString declFile = QString::fromUtf8(decl->fileName(), decl->fileNameLength());
|
|
|
|
|
const QDir dir = QFileInfo(declFile).dir();
|
2010-10-05 09:44:33 +02:00
|
|
|
setDescription(QCoreApplication::translate("CppEditor::InsertDefOperation",
|
2010-10-06 16:33:49 +02:00
|
|
|
"Add Definition in %1")
|
2010-10-06 15:49:59 +02:00
|
|
|
.arg(dir.relativeFilePath(m_loc.fileName())));
|
2010-09-30 12:09:38 +02:00
|
|
|
}
|
2010-09-27 18:01:04 +02:00
|
|
|
|
2011-08-17 11:35:57 +02:00
|
|
|
void performChanges(const CppRefactoringFilePtr &,
|
|
|
|
|
const CppRefactoringChanges &refactoring)
|
2010-09-30 12:09:38 +02:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(m_loc.isValid());
|
2010-09-27 18:01:04 +02:00
|
|
|
|
2011-08-17 11:35:57 +02:00
|
|
|
CppRefactoringFilePtr targetFile = refactoring.file(m_loc.fileName());
|
2010-09-27 18:01:04 +02:00
|
|
|
|
2010-09-30 12:09:38 +02:00
|
|
|
Overview oo;
|
|
|
|
|
oo.setShowFunctionSignatures(true);
|
|
|
|
|
oo.setShowReturnTypes(true);
|
|
|
|
|
oo.setShowArgumentNames(true);
|
|
|
|
|
|
2011-07-28 21:17:28 +02:00
|
|
|
// make target lookup context
|
2011-08-17 11:35:57 +02:00
|
|
|
Document::Ptr targetDoc = targetFile->cppDocument();
|
2011-07-28 21:17:28 +02:00
|
|
|
Scope *targetScope = targetDoc->scopeAt(m_loc.line(), m_loc.column());
|
|
|
|
|
LookupContext targetContext(targetDoc, assistInterface()->snapshot());
|
|
|
|
|
ClassOrNamespace *targetCoN = targetContext.lookupType(targetScope);
|
|
|
|
|
if (!targetCoN)
|
|
|
|
|
targetCoN = targetContext.globalNamespace();
|
|
|
|
|
|
|
|
|
|
// setup rewriting to get minimally qualified names
|
2010-09-30 12:09:38 +02:00
|
|
|
SubstitutionEnvironment env;
|
2011-04-15 16:19:23 +02:00
|
|
|
env.setContext(assistInterface()->context());
|
2010-09-30 12:09:38 +02:00
|
|
|
env.switchScope(m_decl->enclosingScope());
|
2011-07-28 21:17:28 +02:00
|
|
|
UseMinimalNames q(targetCoN);
|
2010-09-30 12:09:38 +02:00
|
|
|
env.enter(&q);
|
2011-04-15 16:19:23 +02:00
|
|
|
Control *control = assistInterface()->context().control().data();
|
2011-07-28 21:17:28 +02:00
|
|
|
|
|
|
|
|
// rewrite the function type
|
2010-09-30 12:09:38 +02:00
|
|
|
FullySpecifiedType tn = rewriteType(m_decl->type(), &env, control);
|
2011-07-28 21:17:28 +02:00
|
|
|
|
|
|
|
|
// rewrite the function name
|
|
|
|
|
QString name;
|
|
|
|
|
const FullySpecifiedType nametype = rewriteType(control->namedType(m_decl->name()), &env, control);
|
|
|
|
|
if (NamedType *nt = nametype.type()->asNamedType()) {
|
|
|
|
|
name = oo(nt->name());
|
|
|
|
|
} else {
|
|
|
|
|
name = oo(LookupContext::fullyQualifiedName(m_decl));
|
|
|
|
|
}
|
2010-09-30 12:09:38 +02:00
|
|
|
|
|
|
|
|
QString defText = oo.prettyType(tn, name) + "\n{\n}";
|
|
|
|
|
|
2011-08-17 11:35:57 +02:00
|
|
|
int targetPos = targetFile->position(m_loc.line(), m_loc.column());
|
|
|
|
|
int targetPos2 = qMax(0, targetFile->position(m_loc.line(), 1) - 1);
|
2010-09-30 12:09:38 +02:00
|
|
|
|
|
|
|
|
Utils::ChangeSet target;
|
|
|
|
|
target.insert(targetPos, m_loc.prefix() + defText + m_loc.suffix());
|
2011-08-17 11:35:57 +02:00
|
|
|
targetFile->setChangeSet(target);
|
|
|
|
|
targetFile->appendIndentRange(Utils::ChangeSet::Range(targetPos2, targetPos));
|
|
|
|
|
targetFile->setOpenEditor(true, targetPos);
|
|
|
|
|
targetFile->apply();
|
2010-09-27 18:01:04 +02:00
|
|
|
}
|
|
|
|
|
|
2010-09-30 12:09:38 +02:00
|
|
|
private:
|
|
|
|
|
Declaration *m_decl;
|
|
|
|
|
InsertionLocation m_loc;
|
|
|
|
|
};
|
2010-09-27 18:01:04 +02:00
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
2011-04-15 16:19:23 +02:00
|
|
|
QList<CppQuickFixOperation::Ptr> DefFromDecl::match(
|
|
|
|
|
const QSharedPointer<const Internal::CppQuickFixAssistInterface> &interface)
|
2010-09-27 18:01:04 +02:00
|
|
|
{
|
2011-04-15 16:19:23 +02:00
|
|
|
const QList<AST *> &path = interface->path();
|
2010-09-27 18:01:04 +02:00
|
|
|
|
|
|
|
|
int idx = path.size() - 1;
|
|
|
|
|
for (; idx >= 0; --idx) {
|
|
|
|
|
AST *node = path.at(idx);
|
2010-09-30 12:09:38 +02:00
|
|
|
if (SimpleDeclarationAST *simpleDecl = node->asSimpleDeclaration()) {
|
|
|
|
|
if (simpleDecl->symbols && ! simpleDecl->symbols->next) {
|
|
|
|
|
if (Symbol *symbol = simpleDecl->symbols->value) {
|
|
|
|
|
if (Declaration *decl = symbol->asDeclaration()) {
|
2010-10-06 16:43:42 +02:00
|
|
|
if (decl->type()->isFunctionType()
|
|
|
|
|
&& !decl->type()->asFunctionType()->isPureVirtual()
|
|
|
|
|
&& decl->enclosingScope()
|
|
|
|
|
&& decl->enclosingScope()->isClass()) {
|
2011-09-26 10:51:13 +02:00
|
|
|
CppRefactoringChanges refactoring(interface->snapshot());
|
|
|
|
|
InsertionPointLocator locator(refactoring);
|
|
|
|
|
QList<CppQuickFixOperation::Ptr> results;
|
|
|
|
|
foreach (const InsertionLocation &loc, locator.methodDefinition(decl)) {
|
|
|
|
|
if (loc.isValid())
|
|
|
|
|
results.append(CppQuickFixOperation::Ptr(new InsertDefOperation(interface, idx, decl, loc)));
|
2010-09-30 12:09:38 +02:00
|
|
|
}
|
2011-09-26 10:51:13 +02:00
|
|
|
return results;
|
2010-09-30 12:09:38 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-09-27 18:01:04 +02:00
|
|
|
|
2010-09-30 12:09:38 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2010-09-27 18:01:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return noResult();
|
|
|
|
|
}
|