Commit d288e399 authored by Lorenz Haas's avatar Lorenz Haas Committed by Nikolai Kosjar
Browse files

CppEditor: Quick fix "Insert (Pure) Virtual Methods"



This quick fix inserts (pure) virtual functions of base classes to the
current class. For selecting the functions which should be inserted and
for choosing the insertion mode (only declarations or with definitions
inside, outside or in the implementation file) a dialog is shown.

Task-number: QTCREATORBUG-2210
Task-number: QTCREATORBUG-2692
Task-number: QTCREATORBUG-3908
Task-number: QTCREATORBUG-5868
Task-number: QTCREATORBUG-7982
Change-Id: I8e94905afcae4778986f4c3925a494e0c6b3b8ee
Reviewed-by: default avatarNikolai Kosjar <nikolai.kosjar@digia.com>
parent 7ef61104
......@@ -1957,6 +1957,19 @@
\endcode
\li Function call or class name
\row
\li Insert (Pure) Virtual Functions
\li Select an insertion mode:
\list
\li Insert only declarations.
\li Insert declarations and the corresponding definitions inside the class.
\li Insert declarations and the corresponding definitions outside the class.
\li Insert declarations and the corresponding definitions in the implementation file
(only if an implementation file exists).
\endlist
\image qtcreator-refactoring-virtual-function-dialog.png
\li Class or base class name
\endtable
......
......@@ -199,6 +199,18 @@ private slots:
void test_quickfix_AssignToLocalVariable_noReturnClass();
void test_quickfix_AssignToLocalVariable_noReturnFunc();
void test_quickfix_InsertVirtualMethods_onlyDecl();
void test_quickfix_InsertVirtualMethods_onlyDeclWithoutVirtual();
void test_quickfix_InsertVirtualMethods_Access();
void test_quickfix_InsertVirtualMethods_Superclass();
void test_quickfix_InsertVirtualMethods_SuperclassOverride();
void test_quickfix_InsertVirtualMethods_PureVirtualOnlyDecl();
void test_quickfix_InsertVirtualMethods_PureVirtualInside();
void test_quickfix_InsertVirtualMethods_inside();
void test_quickfix_InsertVirtualMethods_outside();
void test_quickfix_InsertVirtualMethods_implementationFile();
void test_quickfix_InsertVirtualMethods_notrigger_allImplemented();
// The following tests depend on the projects that are loaded on startup
// and will be skipped in case no projects are loaded.
void test_openEachFile();
......
......@@ -2014,3 +2014,420 @@ void CppEditorPlugin::test_quickfix_AssignToLocalVariable_noReturnFunc()
TestCase data(original, expected);
data.run(&factory);
}
/// Test dialog for insert virtual functions
class InsertVirtualMethodsDialogTest : public InsertVirtualMethodsDialog
{
public:
InsertVirtualMethodsDialogTest(ImplementationMode mode, bool virt, QWidget *parent = 0)
: InsertVirtualMethodsDialog(parent)
{
setImplementationsMode(mode);
setInsertKeywordVirtual(virt);
}
bool gather()
{
return true;
}
ImplementationMode implementationMode() const
{
return m_implementationMode;
}
bool insertKeywordVirtual() const
{
return m_insertKeywordVirtual;
}
};
/// Check: Insert only declarations
void CppEditorPlugin::test_quickfix_InsertVirtualMethods_onlyDecl()
{
const QByteArray original =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n\n"
"class Derived : public Bas@eA {\n"
"};";
const QByteArray expected =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n\n"
"class Derived : public BaseA {\n"
"\n"
" // BaseA interface\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n";
InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest(
InsertVirtualMethodsDialog::ModeOnlyDeclarations, true));
TestCase data(original, expected);
data.run(&factory);
}
/// Check: Insert only declarations vithout virtual keyword
void CppEditorPlugin::test_quickfix_InsertVirtualMethods_onlyDeclWithoutVirtual()
{
const QByteArray original =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n\n"
"class Derived : public Bas@eA {\n"
"};";
const QByteArray expected =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n\n"
"class Derived : public BaseA {\n"
"\n"
" // BaseA interface\n"
"public:\n"
" int virtualFuncA();\n"
"};\n";
InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest(
InsertVirtualMethodsDialog::ModeOnlyDeclarations, false));
TestCase data(original, expected);
data.run(&factory);
}
/// Check: Are access specifiers considered
void CppEditorPlugin::test_quickfix_InsertVirtualMethods_Access()
{
const QByteArray original =
"class BaseA {\n"
"public:\n"
" virtual int a();\n"
"protected:\n"
" virtual int b();\n"
"private:\n"
" virtual int c();\n"
"public slots:\n"
" virtual int d();\n"
"protected slots:\n"
" virtual int e();\n"
"private slots:\n"
" virtual int f();\n"
"signals:\n"
" virtual int g();\n"
"};\n\n"
"class Der@ived : public BaseA {\n"
"};";
const QByteArray expected =
"class BaseA {\n"
"public:\n"
" virtual int a();\n"
"protected:\n"
" virtual int b();\n"
"private:\n"
" virtual int c();\n"
"public slots:\n"
" virtual int d();\n"
"protected slots:\n"
" virtual int e();\n"
"private slots:\n"
" virtual int f();\n"
"signals:\n"
" virtual int g();\n"
"};\n\n"
"class Derived : public BaseA {\n"
"\n"
" // BaseA interface\n"
"public:\n"
" virtual int a();\n\n"
"protected:\n"
" virtual int b();\n\n"
"private:\n"
" virtual int c();\n\n"
"public slots:\n"
" virtual int d();\n\n"
"protected slots:\n"
" virtual int e();\n\n"
"private slots:\n"
" virtual int f();\n\n"
"signals:\n"
" virtual int g();\n"
"};\n";
InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest(
InsertVirtualMethodsDialog::ModeOnlyDeclarations, true));
TestCase data(original, expected);
data.run(&factory);
}
/// Check: Is a base class of a base class considered.
void CppEditorPlugin::test_quickfix_InsertVirtualMethods_Superclass()
{
const QByteArray original =
"class BaseA {\n"
"public:\n"
" virtual int a();\n"
"};\n\n"
"class BaseB : public BaseA {\n"
"public:\n"
" virtual int b();\n"
"};\n\n"
"class Der@ived : public BaseB {\n"
"};";
const QByteArray expected =
"class BaseA {\n"
"public:\n"
" virtual int a();\n"
"};\n\n"
"class BaseB : public BaseA {\n"
"public:\n"
" virtual int b();\n"
"};\n\n"
"class Der@ived : public BaseB {\n"
"\n"
" // BaseB interface\n"
"public:\n"
" virtual int b();\n"
"\n"
" // BaseA interface\n"
"public:\n"
" virtual int a();\n"
"};\n";
InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest(
InsertVirtualMethodsDialog::ModeOnlyDeclarations, true));
TestCase data(original, expected);
data.run(&factory);
}
/// Check: Do not insert reimplemented functions twice.
void CppEditorPlugin::test_quickfix_InsertVirtualMethods_SuperclassOverride()
{
const QByteArray original =
"class BaseA {\n"
"public:\n"
" virtual int a();\n"
"};\n\n"
"class BaseB : public BaseA {\n"
"public:\n"
" virtual int a();\n"
"};\n\n"
"class Der@ived : public BaseB {\n"
"};";
const QByteArray expected =
"class BaseA {\n"
"public:\n"
" virtual int a();\n"
"};\n\n"
"class BaseB : public BaseA {\n"
"public:\n"
" virtual int a();\n"
"};\n\n"
"class Der@ived : public BaseB {\n"
"\n"
" // BaseA interface\n"
"public:\n"
" virtual int a();\n"
"};\n";
InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest(
InsertVirtualMethodsDialog::ModeOnlyDeclarations, true));
TestCase data(original, expected);
data.run(&factory);
}
/// Check: Insert only declarations for pure virtual function
void CppEditorPlugin::test_quickfix_InsertVirtualMethods_PureVirtualOnlyDecl()
{
const QByteArray original =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA() = 0;\n"
"};\n\n"
"class Derived : public Bas@eA {\n"
"};";
const QByteArray expected =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA() = 0;\n"
"};\n\n"
"class Derived : public BaseA {\n"
"\n"
" // BaseA interface\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n";
InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest(
InsertVirtualMethodsDialog::ModeOnlyDeclarations, true));
TestCase data(original, expected);
data.run(&factory);
}
/// Check: Insert pure virtual functions inside class
void CppEditorPlugin::test_quickfix_InsertVirtualMethods_PureVirtualInside()
{
const QByteArray original =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA() = 0;\n"
"};\n\n"
"class Derived : public Bas@eA {\n"
"};";
const QByteArray expected =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA() = 0;\n"
"};\n\n"
"class Derived : public BaseA {\n"
"\n"
" // BaseA interface\n"
"public:\n"
" virtual int virtualFuncA()\n"
" {\n"
" }\n"
"};\n";
InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest(
InsertVirtualMethodsDialog::ModeInsideClass, true));
TestCase data(original, expected);
data.run(&factory);
}
/// Check: Insert inside class
void CppEditorPlugin::test_quickfix_InsertVirtualMethods_inside()
{
const QByteArray original =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n\n"
"class Derived : public Bas@eA {\n"
"};";
const QByteArray expected =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n\n"
"class Derived : public BaseA {\n"
"\n"
" // BaseA interface\n"
"public:\n"
" virtual int virtualFuncA()\n"
" {\n"
" }\n"
"};\n";
InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest(
InsertVirtualMethodsDialog::ModeInsideClass, true));
TestCase data(original, expected);
data.run(&factory);
}
/// Check: Insert outside class
void CppEditorPlugin::test_quickfix_InsertVirtualMethods_outside()
{
const QByteArray original =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n\n"
"class Derived : public Bas@eA {\n"
"};";
const QByteArray expected =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n\n"
"class Derived : public BaseA {\n"
"\n"
" // BaseA interface\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n\n"
"int Derived::virtualFuncA()\n"
"{\n"
"}\n";
InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest(
InsertVirtualMethodsDialog::ModeOutsideClass, true));
TestCase data(original, expected);
data.run(&factory);
}
/// Check: Insert in implementation file
void CppEditorPlugin::test_quickfix_InsertVirtualMethods_implementationFile()
{
QList<TestDocumentPtr> testFiles;
QByteArray original;
QByteArray expected;
// Header File
original =
"class BaseA {\n"
"public:\n"
" virtual int a();\n"
"};\n\n"
"class Derived : public Bas@eA {\n"
"public:\n"
" Derived();\n"
"};";
expected =
"class BaseA {\n"
"public:\n"
" virtual int a();\n"
"};\n\n"
"class Derived : public BaseA {\n"
"public:\n"
" Derived();\n"
"\n"
" // BaseA interface\n"
"public:\n"
" virtual int a();\n"
"};\n";
testFiles << TestDocument::create(original, expected, QLatin1String("file.h"));
// Source File
original = "#include \"file.h\"\n";
expected =
"#include \"file.h\"\n"
"\n\n"
"int Derived::a()\n"
"{\n}\n";
testFiles << TestDocument::create(original, expected, QLatin1String("file.cpp"));
InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest(
InsertVirtualMethodsDialog::ModeImplementationFile, true));
TestCase data(testFiles);
data.run(&factory);
}
/// Check: No trigger: all implemented
void CppEditorPlugin::test_quickfix_InsertVirtualMethods_notrigger_allImplemented()
{
const QByteArray original =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n\n"
"class Derived : public Bas@eA {\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};";
const QByteArray expected =
"class BaseA {\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n\n"
"class Derived : public Bas@eA {\n"
"public:\n"
" virtual int virtualFuncA();\n"
"};\n";
InsertVirtualMethods factory(new InsertVirtualMethodsDialogTest(
InsertVirtualMethodsDialog::ModeOutsideClass, true));
TestCase data(original, expected);
data.run(&factory);
}
This diff is collapsed.
......@@ -36,9 +36,18 @@
#include <extensionsystem/iplugin.h>
#include <QDialog>
QT_BEGIN_NAMESPACE
class QByteArray;
class QCheckBox;
class QComboBox;
class QDialogButtonBox;
class QStandardItem;
class QSortFilterProxyModel;
class QStandardItemModel;
class QString;
class QTreeView;
template <class> class QList;
QT_END_NAMESPACE
......@@ -482,6 +491,78 @@ public:
void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
};
/*!
Insert (pure) virtual functions of a base class.
*/
class InsertVirtualMethodsDialog : public QDialog
{
Q_OBJECT
public:
enum CustomItemRoles {
ClassOrFunction = Qt::UserRole + 1,
Implemented = Qt::UserRole + 2,
PureVirtual = Qt::UserRole + 3,
AccessSpec = Qt::UserRole + 4
};
enum ImplementationMode {
ModeOnlyDeclarations = 0x00000001,
ModeInsideClass = 0x00000002,
ModeOutsideClass = 0x00000004,
ModeImplementationFile = 0x00000008
};
InsertVirtualMethodsDialog(QWidget *parent = 0);
void initGui();
void initData();
virtual ImplementationMode implementationMode() const;
void setImplementationsMode(ImplementationMode mode);
virtual bool insertKeywordVirtual() const;
void setInsertKeywordVirtual(bool insert);
void setHasImplementationFile(bool file);
void setHasReimplementedFunctions(bool functions);
bool hideReimplementedFunctions() const;
virtual bool gather();
private slots:
void updateCheckBoxes(QStandardItem *item);
void setHideReimplementedFunctions(bool hide);
private:
QTreeView *m_view;
QCheckBox *m_hideReimplementedFunctions;
QComboBox *m_insertMode;
QCheckBox *m_virtualKeyword;
QDialogButtonBox *m_buttons;
QList<bool> m_expansionStateNormal;
QList<bool> m_expansionStateReimp;
bool m_hasImplementationFile;
bool m_hasReimplementedFunctions;
void saveExpansionState();
void restoreExpansionState();
protected:
ImplementationMode m_implementationMode;
bool m_insertKeywordVirtual;
public:
QStandardItemModel *classFunctionModel;
QSortFilterProxyModel *classFunctionFilterModel;
};
class InsertVirtualMethods: public CppQuickFixFactory
{
Q_OBJECT
public:
InsertVirtualMethods(InsertVirtualMethodsDialog *dialog = new InsertVirtualMethodsDialog);
~InsertVirtualMethods();
void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
private:
InsertVirtualMethodsDialog *m_dialog;
};
} // namespace Internal
} // namespace CppEditor
......
......@@ -42,33 +42,6 @@ using namespace CppTools;
namespace {
static QString generate(InsertionPointLocator::AccessSpec xsSpec)
{
switch (xsSpec) {
default:
case InsertionPointLocator::Public:
return QLatin1String("public:\n");
case InsertionPointLocator::Protected:
return QLatin1String("protected:\n");
case InsertionPointLocator::Private:
return QLatin1String("private:\n");
case InsertionPointLocator::PublicSlot:
return QLatin1String("public slots:\n");
case InsertionPointLocator::ProtectedSlot:
return QLatin1String("protected slots:\n");
case InsertionPointLocator::PrivateSlot:
return QLatin1String("private slots:\n");
case InsertionPointLocator::Signals:
return QLatin1String("signals:\n");
}
}
static int ordering(InsertionPointLocator::AccessSpec xsSpec)
{
static QList<InsertionPointLocator::AccessSpec> order = QList<InsertionPointLocator::AccessSpec>()
......@@ -161,7 +134,7 @@ protected:
if (needsLeadingEmptyLine)
prefix += QLatin1String("\n");
if (needsPrefix)
prefix += generate(_xsSpec);
prefix += InsertionPointLocator::accessSpecToString(_xsSpec);