2010-07-08 16:40:46 +02:00
|
|
|
/**************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** This file is part of Qt Creator
|
|
|
|
|
**
|
|
|
|
|
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|
|
|
|
**
|
|
|
|
|
** Contact: Nokia Corporation (qt-info@nokia.com)
|
|
|
|
|
**
|
|
|
|
|
** Commercial Usage
|
|
|
|
|
**
|
|
|
|
|
** Licensees holding valid Qt Commercial licenses may use this file in
|
|
|
|
|
** accordance with the Qt Commercial License Agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
|
** a written agreement between you and Nokia.
|
|
|
|
|
**
|
|
|
|
|
** GNU Lesser General Public License Usage
|
|
|
|
|
**
|
|
|
|
|
** Alternatively, 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.
|
|
|
|
|
**
|
|
|
|
|
** If you are unsure which license is appropriate for your use, please
|
|
|
|
|
** contact the sales department at http://qt.nokia.com/contact.
|
|
|
|
|
**
|
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
2010-09-02 15:17:57 +02:00
|
|
|
#include "cppinsertdecldef.h"
|
2010-07-08 16:40:46 +02:00
|
|
|
|
|
|
|
|
#include <AST.h>
|
|
|
|
|
#include <ASTVisitor.h>
|
|
|
|
|
#include <CoreTypes.h>
|
|
|
|
|
#include <Names.h>
|
|
|
|
|
#include <Symbols.h>
|
|
|
|
|
#include <TranslationUnit.h>
|
|
|
|
|
#include <cplusplus/ASTPath.h>
|
2010-07-27 15:29:16 +02:00
|
|
|
#include <cplusplus/InsertionPointLocator.h>
|
2010-07-08 16:40:46 +02:00
|
|
|
#include <cplusplus/LookupContext.h>
|
|
|
|
|
#include <cplusplus/Overview.h>
|
|
|
|
|
|
|
|
|
|
#include <QtCore/QCoreApplication>
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
using CppEditor::CppRefactoringChanges;
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
2010-09-27 18:01:04 +02:00
|
|
|
class InsertDeclOperation: public CppQuickFixOperation
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
public:
|
2010-09-27 18:01:04 +02:00
|
|
|
InsertDeclOperation(const CppQuickFixState &state, int priority,
|
|
|
|
|
const QString &targetFileName, const Class *targetSymbol,
|
|
|
|
|
InsertionPointLocator::AccessSpec xsSpec,
|
|
|
|
|
const QString &decl)
|
2010-07-26 13:06:33 +02:00
|
|
|
: CppQuickFixOperation(state, priority)
|
|
|
|
|
, 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-09-15 16:47:30 +02:00
|
|
|
setDescription(QCoreApplication::tr("Add %1 declaration",
|
2010-07-30 14:55:11 +02:00
|
|
|
"CppEditor::DeclFromDef").arg(type));
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
2010-07-08 16:40:46 +02:00
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
void performChanges(CppRefactoringFile *, CppRefactoringChanges *refactoring)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
2010-09-27 18:01:04 +02:00
|
|
|
InsertionPointLocator locator(state().snapshot());
|
|
|
|
|
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
|
|
|
|
2010-09-27 18:01:04 +02:00
|
|
|
CppRefactoringFile targetFile = refactoring->file(m_targetFileName);
|
2010-08-12 11:34:48 +02:00
|
|
|
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);
|
2010-08-12 11:34:48 +02:00
|
|
|
targetFile.change(target);
|
|
|
|
|
targetFile.indent(Utils::ChangeSet::Range(targetPosition2, targetPosition1));
|
2010-07-26 13:06:33 +02:00
|
|
|
|
2010-09-23 18:22:07 +02:00
|
|
|
const int prefixLineCount = loc.prefix().count(QLatin1Char('\n'));
|
|
|
|
|
refactoring->activateEditor(m_targetFileName, loc.line() + prefixLineCount,
|
|
|
|
|
qMax(((int) loc.column()) - 1, 0));
|
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
|
|
|
|
2010-07-26 13:06:33 +02:00
|
|
|
QList<CppQuickFixOperation::Ptr> DeclFromDef::match(const CppQuickFixState &state)
|
2010-07-08 16:40:46 +02:00
|
|
|
{
|
2010-07-26 13:06:33 +02:00
|
|
|
const QList<AST *> &path = state.path();
|
2010-08-13 12:49:11 +02:00
|
|
|
const CppRefactoringFile &file = state.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()) {
|
|
|
|
|
if (file.isCursorOn(declId)) {
|
|
|
|
|
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-07-26 13:06:33 +02:00
|
|
|
if (ClassOrNamespace *targetBinding = state.context().lookupParent(method)) {
|
2010-07-08 16:40:46 +02:00
|
|
|
foreach (Symbol *s, targetBinding->symbols()) {
|
|
|
|
|
if (Class *clazz = s->asClass()) {
|
2010-07-30 14:55:11 +02:00
|
|
|
QList<CppQuickFixOperation::Ptr> results;
|
|
|
|
|
const QLatin1String fn(clazz->fileName());
|
|
|
|
|
const QString decl = generateDeclaration(state,
|
|
|
|
|
method,
|
|
|
|
|
targetBinding);
|
2010-09-27 18:01:04 +02:00
|
|
|
results.append(
|
|
|
|
|
singleResult(
|
|
|
|
|
new InsertDeclOperation(state, idx, fn, clazz,
|
|
|
|
|
InsertionPointLocator::Public,
|
|
|
|
|
decl)));
|
|
|
|
|
results.append(
|
|
|
|
|
singleResult(
|
|
|
|
|
new InsertDeclOperation(state, idx, fn, clazz,
|
|
|
|
|
InsertionPointLocator::Protected,
|
|
|
|
|
decl)));
|
|
|
|
|
results.append(
|
|
|
|
|
singleResult(
|
|
|
|
|
new InsertDeclOperation(state, idx, fn, clazz,
|
|
|
|
|
InsertionPointLocator::Private,
|
|
|
|
|
decl)));
|
|
|
|
|
results.append(
|
|
|
|
|
singleResult(
|
|
|
|
|
new InsertDeclOperation(state, idx, fn, clazz,
|
|
|
|
|
InsertionPointLocator::PublicSlot,
|
|
|
|
|
decl)));
|
|
|
|
|
results.append(
|
|
|
|
|
singleResult(
|
|
|
|
|
new InsertDeclOperation(state, idx, fn, clazz,
|
|
|
|
|
InsertionPointLocator::ProtectedSlot,
|
|
|
|
|
decl)));
|
|
|
|
|
results.append(
|
|
|
|
|
singleResult(
|
|
|
|
|
new InsertDeclOperation(state, idx, fn, clazz,
|
|
|
|
|
InsertionPointLocator::PrivateSlot,
|
|
|
|
|
decl)));
|
2010-07-30 14:55:11 +02:00
|
|
|
return results;
|
2010-09-22 16:42:49 +02:00
|
|
|
} //! \todo support insertion of non-methods into namespaces
|
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
|
|
|
}
|
|
|
|
|
|
2010-08-02 14:13:42 +02:00
|
|
|
QString DeclFromDef::generateDeclaration(const CppQuickFixState &,
|
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 {
|
|
|
|
|
|
|
|
|
|
static inline bool hasFunctionType(DeclarationAST *decl)
|
|
|
|
|
{
|
|
|
|
|
if (decl->asFunctionDefinition())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (SimpleDeclarationAST *ast = decl->asSimpleDeclaration())
|
|
|
|
|
if (ast->symbols && ast->symbols->value && !ast->symbols->next)
|
|
|
|
|
if (Declaration *decl = ast->symbols->value->asDeclaration())
|
|
|
|
|
if (FullySpecifiedType ty = decl->type())
|
|
|
|
|
return ty->asFunctionType();
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QPair<DeclarationAST *, DeclarationAST *> findSurroundingDeclarations(
|
|
|
|
|
DeclarationListAST *members,
|
|
|
|
|
DeclarationAST *decl)
|
|
|
|
|
{
|
|
|
|
|
bool found = false;
|
|
|
|
|
DeclarationAST *last = 0, *next = 0, *prev = 0;
|
|
|
|
|
DeclarationListAST *iter = members;
|
|
|
|
|
for (; iter; iter = iter->next) {
|
|
|
|
|
DeclarationAST *value = iter->value;
|
|
|
|
|
if (value == decl) {
|
|
|
|
|
prev = last;
|
|
|
|
|
found = true;
|
|
|
|
|
} else if (hasFunctionType(value)) {
|
|
|
|
|
if (found) {
|
|
|
|
|
next = value;
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
last = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return qMakePair(prev, next);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
|
|
QList<CppQuickFixOperation::Ptr> DefFromDecl::match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
#if 0
|
|
|
|
|
qDebug() << Q_FUNC_INFO;
|
|
|
|
|
|
|
|
|
|
const QList<AST *> &path = state.path();
|
|
|
|
|
const CppRefactoringFile &file = state.currentFile();
|
|
|
|
|
|
|
|
|
|
DeclaratorAST *declAST = 0;
|
|
|
|
|
ClassSpecifierAST *classSpec = 0;
|
|
|
|
|
int idx = path.size() - 1;
|
|
|
|
|
for (; idx >= 0; --idx) {
|
|
|
|
|
AST *node = path.at(idx);
|
|
|
|
|
if (ClassSpecifierAST *clazz = node->asClassSpecifier()) {
|
|
|
|
|
classSpec = clazz;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (idx <= 1) continue;
|
|
|
|
|
DeclaratorIdAST *declId = node->asDeclaratorId();
|
|
|
|
|
if (!declId) continue;
|
|
|
|
|
|
|
|
|
|
if (!file.isCursorOn(declId)) continue;
|
|
|
|
|
|
|
|
|
|
DeclaratorAST *candidate = path.at(idx - 1)->asDeclarator();
|
|
|
|
|
if (!candidate) continue;
|
|
|
|
|
if (!candidate->postfix_declarator_list) continue;
|
|
|
|
|
if (!candidate->postfix_declarator_list->value) continue;
|
|
|
|
|
if (candidate->postfix_declarator_list->next) continue;
|
|
|
|
|
FunctionDeclaratorAST *funDecl = candidate->postfix_declarator_list->value->asFunctionDeclarator();
|
|
|
|
|
if (!funDecl) continue;
|
|
|
|
|
if (funDecl->symbol->asFunctionType())
|
|
|
|
|
declAST = candidate;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!declAST || !classSpec || !classSpec->symbol)
|
|
|
|
|
return noResult();
|
|
|
|
|
|
|
|
|
|
if (!declAST->symbols || !declAST->symbols->value || declAST->symbols->next)
|
|
|
|
|
return noResult();
|
|
|
|
|
|
|
|
|
|
Declaration *decl = declAST->symbols->value->asDeclaration();
|
|
|
|
|
if (!decl)
|
|
|
|
|
return noResult();
|
|
|
|
|
|
|
|
|
|
Function *funTy = decl->type()->asFunctionType();
|
|
|
|
|
if (!funTy)
|
|
|
|
|
return noResult();
|
|
|
|
|
|
|
|
|
|
qDebug() << "-> Found funTy.";
|
|
|
|
|
|
|
|
|
|
QPair<DeclarationAST *, DeclarationAST *> surroundingNodes =
|
|
|
|
|
findSurroundingDeclarations(classSpec->member_specifier_list, declAST);
|
|
|
|
|
qDebug() << "->("<<surroundingNodes.first<<","<<surroundingNodes.second<<")";
|
|
|
|
|
if (surroundingNodes.first)
|
|
|
|
|
if (SimpleDeclarationAST *sd = surroundingNodes.first->asSimpleDeclaration())
|
|
|
|
|
qDebug()<<"-->prev@"<<sd->symbols->value->line()<<sd->symbols->value->column();
|
|
|
|
|
if (surroundingNodes.second)
|
|
|
|
|
if (SimpleDeclarationAST *sd=surroundingNodes.second->asSimpleDeclaration())
|
|
|
|
|
qDebug()<<"-->next@"<<sd->symbols->value->line()<<sd->symbols->value->column();
|
|
|
|
|
#endif
|
|
|
|
|
// if (ClassOrNamespace *targetBinding = state.context().lookupParent(method)) {
|
|
|
|
|
// foreach (Symbol *s, targetBinding->symbols()) {
|
|
|
|
|
// if (Class *clazz = s->asClass()) {
|
|
|
|
|
// QList<CppQuickFixOperation::Ptr> results;
|
|
|
|
|
// const QLatin1String fn(clazz->fileName());
|
|
|
|
|
// const QString decl = generateDeclaration(state,
|
|
|
|
|
// method,
|
|
|
|
|
// targetBinding);
|
|
|
|
|
// results.append(
|
|
|
|
|
// singleResult(
|
|
|
|
|
// new InsertDeclOperation(state, idx, fn, clazz,
|
|
|
|
|
// InsertionPointLocator::Public,
|
|
|
|
|
// decl)));
|
|
|
|
|
// results.append(
|
|
|
|
|
// singleResult(
|
|
|
|
|
// new InsertDeclOperation(state, idx, fn, clazz,
|
|
|
|
|
// InsertionPointLocator::Protected,
|
|
|
|
|
// decl)));
|
|
|
|
|
// results.append(
|
|
|
|
|
// singleResult(
|
|
|
|
|
// new InsertDeclOperation(state, idx, fn, clazz,
|
|
|
|
|
// InsertionPointLocator::Private,
|
|
|
|
|
// decl)));
|
|
|
|
|
// results.append(
|
|
|
|
|
// singleResult(
|
|
|
|
|
// new InsertDeclOperation(state, idx, fn, clazz,
|
|
|
|
|
// InsertionPointLocator::PublicSlot,
|
|
|
|
|
// decl)));
|
|
|
|
|
// results.append(
|
|
|
|
|
// singleResult(
|
|
|
|
|
// new InsertDeclOperation(state, idx, fn, clazz,
|
|
|
|
|
// InsertionPointLocator::ProtectedSlot,
|
|
|
|
|
// decl)));
|
|
|
|
|
// results.append(
|
|
|
|
|
// singleResult(
|
|
|
|
|
// new InsertDeclOperation(state, idx, fn, clazz,
|
|
|
|
|
// InsertionPointLocator::PrivateSlot,
|
|
|
|
|
// decl)));
|
|
|
|
|
// return results;
|
|
|
|
|
// } //! \todo support insertion into namespaces
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
return noResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString DefFromDecl::generateDefinition(const CppQuickFixState &,
|
|
|
|
|
Function *method,
|
|
|
|
|
ClassOrNamespace *targetBinding)
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(targetBinding);
|
|
|
|
|
|
|
|
|
|
Overview oo;
|
|
|
|
|
oo.setShowFunctionSignatures(true);
|
|
|
|
|
oo.setShowReturnTypes(true);
|
|
|
|
|
oo.setShowArgumentNames(true);
|
|
|
|
|
|
|
|
|
|
QString decl;
|
|
|
|
|
decl += oo(method->type(), method->unqualifiedName());
|
|
|
|
|
decl += QLatin1String(";\n");
|
|
|
|
|
|
|
|
|
|
return decl;
|
|
|
|
|
}
|