Commit bc3c51f4 authored by Christian Kamm's avatar Christian Kamm

C++: Add quick fix for Q_PROPERTY.

At the moment, it inserts implementations inline.

Done-with: Leandro Melo
parent 506fb9e1
......@@ -26,7 +26,8 @@ HEADERS += cppplugin.h \
cppqtstyleindenter.h \
cppautocompleter.h \
cppcompleteswitch.h \
cppsnippetprovider.h
cppsnippetprovider.h \
cppinsertqtpropertymembers.h
SOURCES += cppplugin.cpp \
cppeditor.cpp \
......@@ -47,7 +48,8 @@ SOURCES += cppplugin.cpp \
cppqtstyleindenter.cpp \
cppautocompleter.cpp \
cppcompleteswitch.cpp \
cppsnippetprovider.cpp
cppsnippetprovider.cpp \
cppinsertqtpropertymembers.cpp
RESOURCES += cppeditor.qrc
OTHER_FILES += CppEditor.mimetypes.xml
/**************************************************************************
**
** 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.
**
**************************************************************************/
#include "cppinsertqtpropertymembers.h"
#include <AST.h>
#include <Token.h>
#include <cplusplus/Overview.h>
#include <cpptools/insertionpointlocator.h>
#include <cpptools/cpprefactoringchanges.h>
#include <cppeditor/cppquickfix.h>
using namespace CPlusPlus;
using namespace CppTools;
using namespace TextEditor;
using namespace Utils;
using namespace CppEditor;
using namespace CppEditor::Internal;
QList<CppQuickFixOperation::Ptr> InsertQtPropertyMembers::match(const CppQuickFixState &state)
{
const QList<AST *> &path = state.path();
if (path.isEmpty())
return noResult();
AST * const ast = path.last();
QtPropertyDeclarationAST *qtPropertyDeclaration = ast->asQtPropertyDeclaration();
if (!qtPropertyDeclaration)
return noResult();
ClassSpecifierAST *klass = 0;
for (int i = path.size() - 2; i >= 0; --i) {
klass = path.at(i)->asClassSpecifier();
if (klass)
break;
}
if (!klass)
return noResult();
CppRefactoringChanges refactoring(state.snapshot());
const CppRefactoringFile &file = refactoring.file(state.document()->fileName());
const QString propertyName = file.textOf(qtPropertyDeclaration->property_name);
QString getterName;
QString setterName;
QString signalName;
int generateFlags;
for (QtPropertyDeclarationItemListAST *it = qtPropertyDeclaration->property_declaration_item_list;
it; it = it->next) {
const QString tokenString = file.tokenAt(it->value->item_name_token).spell();
if (tokenString == QLatin1String("READ")) {
getterName = file.textOf(it->value->expression);
generateFlags |= GenerateGetter;
} else if (tokenString == QLatin1String("WRITE")) {
setterName = file.textOf(it->value->expression);
generateFlags |= GenerateSetter;
} else if (tokenString == QLatin1String("NOTIFY")) {
signalName = file.textOf(it->value->expression);
generateFlags |= GenerateSignal;
}
}
QString storageName = QString("m_%1").arg(propertyName);
generateFlags |= GenerateStorage;
Class *c = klass->symbol;
Overview overview;
for (unsigned i = 0; i < c->memberCount(); ++i) {
Symbol *member = c->memberAt(i);
FullySpecifiedType type = member->type();
if (member->asFunction() || (type.isValid() && type->asFunctionType())) {
const QString name = overview(member->name());
if (name == getterName) {
generateFlags &= ~GenerateGetter;
} else if (name == setterName) {
generateFlags &= ~GenerateSetter;
} else if (name == signalName) {
generateFlags &= ~GenerateSignal;
}
} else if (member->asDeclaration()) {
const QString name = overview(member->name());
if (name == storageName)
generateFlags &= ~GenerateStorage;
}
}
if (getterName.isEmpty() && setterName.isEmpty() && signalName.isEmpty())
return noResult();
return singleResult(new Operation(state, path.size() - 1, qtPropertyDeclaration, c,
generateFlags,
getterName, setterName, signalName, storageName));
}
InsertQtPropertyMembers::Operation::Operation(
const CppQuickFixState &state, int priority, QtPropertyDeclarationAST *declaration, Class *klass,
int generateFlags, const QString &getterName, const QString &setterName, const QString &signalName,
const QString &storageName)
: CppQuickFixOperation(state, priority)
, m_declaration(declaration)
, m_class(klass)
, m_generateFlags(generateFlags)
, m_getterName(getterName)
, m_setterName(setterName)
, m_signalName(signalName)
, m_storageName(storageName)
{
QString desc = InsertQtPropertyMembers::tr("Generate missing Q_PROPERTY members...");
setDescription(desc);
}
void InsertQtPropertyMembers::Operation::performChanges(CppRefactoringFile *file, CppRefactoringChanges *refactoring)
{
InsertionPointLocator locator(refactoring);
Utils::ChangeSet declarations;
const QString typeName = file->textOf(m_declaration->type_id);
const QString propertyName = file->textOf(m_declaration->property_name);
// getter declaration
if (m_generateFlags & GenerateGetter) {
// const QString getterDeclaration = QString("%1 %2() const;").arg(typeName, getterName);
const QString getterDeclaration = QString("%1 %2() const\n{\nreturn %3;\n}\n").arg(typeName, m_getterName, m_storageName);
InsertionLocation getterLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Public);
Q_ASSERT(getterLoc.isValid());
insertAndIndent(file, &declarations, getterLoc, getterDeclaration);
}
// setter declaration
if (m_generateFlags & GenerateSetter) {
// const QString setterDeclaration = QString("void %1(%2 arg);").arg(setterName, typeName);
QString setterDeclaration = QString("void %1(%2 arg)\n{\n").arg(m_setterName, typeName);
if (!m_signalName.isEmpty()) {
setterDeclaration += QString("if (%1 != arg) {\n%1 = arg;\nemit %2(arg);\n}\n}\n").arg(m_storageName, m_signalName);
} else {
setterDeclaration += QString("%1 = arg;\n}\n").arg(m_storageName);
}
InsertionLocation setterLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::PublicSlot);
Q_ASSERT(setterLoc.isValid());
insertAndIndent(file, &declarations, setterLoc, setterDeclaration);
}
// signal declaration
if (m_generateFlags & GenerateSignal) {
const QString declaration = QString("void %1(%2 arg);\n").arg(m_signalName, typeName);
InsertionLocation loc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Signals);
Q_ASSERT(loc.isValid());
insertAndIndent(file, &declarations, loc, declaration);
}
// storage
if (m_generateFlags & GenerateStorage) {
const QString storageDeclaration = QString("%1 m_%2;\n").arg(typeName, propertyName);
InsertionLocation storageLoc = locator.methodDeclarationInClass(file->fileName(), m_class, InsertionPointLocator::Private);
Q_ASSERT(storageLoc.isValid());
insertAndIndent(file, &declarations, storageLoc, storageDeclaration);
}
file->change(declarations);
}
void InsertQtPropertyMembers::Operation::insertAndIndent(RefactoringFile *file, ChangeSet *changeSet, const InsertionLocation &loc, const QString &text)
{
int targetPosition1 = file->position(loc.line(), loc.column());
int targetPosition2 = qMax(0, file->position(loc.line(), 1) - 1);
changeSet->insert(targetPosition1, loc.prefix() + text + loc.suffix());
file->indent(Utils::ChangeSet::Range(targetPosition2, targetPosition1));
}
/**************************************************************************
**
** 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.
**
**************************************************************************/
#ifndef CPPINSERTQTPROPERTYMEMBERS_H
#define CPPINSERTQTPROPERTYMEMBERS_H
#include <cppeditor/cppquickfix.h>
#include <QtCore/QString>
namespace CPlusPlus {
class QtPropertyDeclarationAST;
class Class;
}
namespace TextEditor {
class RefactoringFile;
}
namespace Utils {
class ChangeSet;
}
namespace CppTools {
class InsertionLocation;
}
namespace CppEditor {
namespace Internal {
class InsertQtPropertyMembers : public CppQuickFixFactory
{
Q_OBJECT
public:
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state);
private:
enum GenerateFlag {
GenerateGetter = 1 << 0,
GenerateSetter = 1 << 1,
GenerateSignal = 1 << 2,
GenerateStorage = 1 << 3
};
class Operation: public CppQuickFixOperation
{
public:
Operation(const CppQuickFixState &state, int priority,
CPlusPlus::QtPropertyDeclarationAST *declaration, CPlusPlus::Class *klass,
int generateFlags,
const QString &getterName, const QString &setterName, const QString &signalName,
const QString &storageName);
virtual void performChanges(CppTools::CppRefactoringFile *file,
CppTools::CppRefactoringChanges *refactoring);
private:
void insertAndIndent(TextEditor::RefactoringFile *file, Utils::ChangeSet *changeSet,
const CppTools::InsertionLocation &loc, const QString &text);
CPlusPlus::QtPropertyDeclarationAST *m_declaration;
CPlusPlus::Class *m_class;
int m_generateFlags;
QString m_getterName;
QString m_setterName;
QString m_signalName;
QString m_storageName;
};
};
} // namespace Internal
} // namespace CppEditor
#endif // CPPINSERTQTPROPERTYMEMBERS_H
......@@ -31,6 +31,7 @@
#include "cppeditor.h"
#include "cppquickfix.h"
#include "cppinsertdecldef.h"
#include "cppinsertqtpropertymembers.h"
#include "cppquickfixcollector.h"
#include <ASTVisitor.h>
......@@ -53,6 +54,7 @@
#include <cplusplus/CppRewriter.h>
#include <cpptools/cpptoolsconstants.h>
#include <cpptools/cpprefactoringchanges.h>
#include <cpptools/insertionpointlocator.h>
#include <extensionsystem/iplugin.h>
#include <QtGui/QApplication>
......@@ -1588,6 +1590,7 @@ void CppQuickFixCollector::registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
plugIn->addAutoReleasedObject(new FixForwardDeclarationOp);
plugIn->addAutoReleasedObject(new AddLocalDeclarationOp);
plugIn->addAutoReleasedObject(new ToCamelCaseConverter);
plugIn->addAutoReleasedObject(new Internal::InsertQtPropertyMembers);
plugIn->addAutoReleasedObject(new Internal::DeclFromDef);
plugIn->addAutoReleasedObject(new Internal::DefFromDecl);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment