Commit c6a7fb8c authored by Nikolai Kosjar's avatar Nikolai Kosjar

C++: Refactor quick fixes

 - Put declarations into quickfixes.h to simplify testing
 - Give the factories more meaningful names

Change-Id: If74c29a8c17819d5369ffa3df94d146b14e53af9
Reviewed-by: default avatarErik Verbruggen <erik.verbruggen@digia.com>
parent 986fc8bf
......@@ -22,6 +22,7 @@ HEADERS += cppplugin.h \
cppinsertqtpropertymembers.h \
cppquickfixassistant.h \
cppquickfix.h \
cppquickfixes.h \
cppfunctiondecldeflink.h
SOURCES += cppplugin.cpp \
......
......@@ -54,6 +54,7 @@ QtcPlugin {
"cppquickfixassistant.cpp",
"cppquickfixassistant.h",
"cppquickfixes.cpp",
"cppquickfixes.h",
"cppsnippetprovider.cpp",
"cppsnippetprovider.h",
"cpptypehierarchy.cpp",
......
......@@ -151,7 +151,7 @@ Class *isMemberFunction(const LookupContext &context, Function *function)
} // anonymous namespace
void DeclFromDef::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
void InsertDeclFromDef::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
const QList<AST *> &path = interface->path();
CppRefactoringFilePtr file = interface->currentFile();
......@@ -287,7 +287,7 @@ private:
} // anonymous namespace
void DefFromDecl::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
void InsertDefFromDecl::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
const QList<AST *> &path = interface->path();
......@@ -319,11 +319,11 @@ void DefFromDecl::match(const CppQuickFixInterface &interface, QuickFixOperation
namespace {
class GetterSetterOperation : public CppQuickFixOperation
class GenerateGetterSetterOperation : public CppQuickFixOperation
{
public:
GetterSetterOperation(const QSharedPointer<const CppQuickFixAssistInterface> &interface,
bool testMode = false)
GenerateGetterSetterOperation(const QSharedPointer<const CppQuickFixAssistInterface> &interface,
bool testMode = false)
: CppQuickFixOperation(interface)
, m_variableName(0)
, m_declaratorId(0)
......@@ -602,9 +602,9 @@ public:
} // namespace
void GetterSetter::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
void GenerateGetterSetter::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
GetterSetterOperation *op = new GetterSetterOperation(interface, m_testMode);
GenerateGetterSetterOperation *op = new GenerateGetterSetterOperation(interface, m_testMode);
if (op->isValid())
result.append(CppQuickFixOperation::Ptr(op));
else
......
......@@ -35,13 +35,13 @@
namespace CppEditor {
namespace Internal {
class DeclFromDef: public CppQuickFixFactory
class InsertDeclFromDef: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
};
class DefFromDecl: public CppQuickFixFactory
class InsertDefFromDecl: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
......@@ -53,10 +53,10 @@ public:
void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
};
class GetterSetter : public CppQuickFixFactory
class GenerateGetterSetter : public CppQuickFixFactory
{
public:
GetterSetter(const bool testMode = false) : m_testMode(testMode) {}
GenerateGetterSetter(const bool testMode = false) : m_testMode(testMode) {}
void match(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result);
private:
const bool m_testMode;
......
......@@ -38,6 +38,7 @@
#include "cpptypehierarchy.h"
#include "cppsnippetprovider.h"
#include "cppquickfixassistant.h"
#include "cppquickfixes.h"
#include <coreplugin/icore.h>
#include <coreplugin/coreconstants.h>
......@@ -187,7 +188,7 @@ bool CppPlugin::initialize(const QStringList & /*arguments*/, QString *errorMess
m_quickFixProvider = new CppQuickFixAssistProvider;
addAutoReleasedObject(m_quickFixProvider);
registerQuickFixes(this);
CppEditor::Internal::registerQuickFixes(this);
QObject *core = Core::ICore::instance();
CppFileWizard::BaseFileWizardParameters wizardParameters(Core::IWizard::FileWizard);
......
......@@ -90,18 +90,18 @@ private slots:
#ifdef WITH_TESTS
private slots: // quickfix tests
void test_quickfix_GetterSetter_basicGetterWithPrefix();
void test_quickfix_GetterSetter_basicGetterWithoutPrefix();
void test_quickfix_GetterSetter_customType();
void test_quickfix_GetterSetter_constMember();
void test_quickfix_GetterSetter_pointerToNonConst();
void test_quickfix_GetterSetter_pointerToConst();
void test_quickfix_GetterSetter_staticMember();
void test_quickfix_GetterSetter_secondDeclarator();
void test_quickfix_GetterSetter_triggeringRightAfterPointerSign();
void test_quickfix_GetterSetter_notTriggeringOnMemberFunction();
void test_quickfix_GetterSetter_notTriggeringOnMemberArray();
void test_quickfix_GetterSetter_notTriggeringWhenGetterOrSetterExist();
void test_quickfix_GenerateGetterSetter_basicGetterWithPrefix();
void test_quickfix_GenerateGetterSetter_basicGetterWithoutPrefix();
void test_quickfix_GenerateGetterSetter_customType();
void test_quickfix_GenerateGetterSetter_constMember();
void test_quickfix_GenerateGetterSetter_pointerToNonConst();
void test_quickfix_GenerateGetterSetter_pointerToConst();
void test_quickfix_GenerateGetterSetter_staticMember();
void test_quickfix_GenerateGetterSetter_secondDeclarator();
void test_quickfix_GenerateGetterSetter_triggeringRightAfterPointerSign();
void test_quickfix_GenerateGetterSetter_notTriggeringOnMemberFunction();
void test_quickfix_GenerateGetterSetter_notTriggeringOnMemberArray();
void test_quickfix_GenerateGetterSetter_notTriggeringWhenGetterOrSetterExist();
#endif // WITH_TESTS
private:
......
......@@ -194,7 +194,7 @@ void TestCase::run(CppQuickFixFactory *factory, const QByteArray &expected,
/// 1. If the name does not start with ("m_" or "_") and does not
/// end with "_", we are forced to prefix the getter with "get".
/// 2. Setter: Use pass by value on integer/float and pointer types.
void CppPlugin::test_quickfix_GetterSetter_basicGetterWithPrefix()
void CppPlugin::test_quickfix_GenerateGetterSetter_basicGetterWithPrefix()
{
TestCase data("\n"
"class Something\n"
......@@ -224,14 +224,14 @@ void CppPlugin::test_quickfix_GetterSetter_basicGetterWithPrefix()
"\n"
;
GetterSetter factory(/*testMode=*/ true);
GenerateGetterSetter factory(/*testMode=*/ true);
data.run(&factory, expected);
}
/// Checks:
/// 1. Getter: "get" prefix is not necessary.
/// 2. Setter: Parameter name is base name.
void CppPlugin::test_quickfix_GetterSetter_basicGetterWithoutPrefix()
void CppPlugin::test_quickfix_GenerateGetterSetter_basicGetterWithoutPrefix()
{
TestCase data("\n"
"class Something\n"
......@@ -261,13 +261,13 @@ void CppPlugin::test_quickfix_GetterSetter_basicGetterWithoutPrefix()
"\n"
;
GetterSetter factory(/*testMode=*/ true);
GenerateGetterSetter factory(/*testMode=*/ true);
data.run(&factory, expected);
}
/// Check: Setter: Use pass by reference for parameters which
/// are not integer, float or pointers.
void CppPlugin::test_quickfix_GetterSetter_customType()
void CppPlugin::test_quickfix_GenerateGetterSetter_customType()
{
TestCase data("\n"
"class Something\n"
......@@ -297,14 +297,14 @@ void CppPlugin::test_quickfix_GetterSetter_customType()
"\n"
;
GetterSetter factory(/*testMode=*/ true);
GenerateGetterSetter factory(/*testMode=*/ true);
data.run(&factory, expected);
}
/// Checks:
/// 1. Setter: No setter is generated for const members.
/// 2. Getter: Return a non-const type since it pass by value anyway.
void CppPlugin::test_quickfix_GetterSetter_constMember()
void CppPlugin::test_quickfix_GenerateGetterSetter_constMember()
{
TestCase data("\n"
"class Something\n"
......@@ -328,12 +328,12 @@ void CppPlugin::test_quickfix_GetterSetter_constMember()
"\n"
;
GetterSetter factory(/*testMode=*/ true);
GenerateGetterSetter factory(/*testMode=*/ true);
data.run(&factory, expected);
}
/// Checks: No special treatment for pointer to non const.
void CppPlugin::test_quickfix_GetterSetter_pointerToNonConst()
void CppPlugin::test_quickfix_GenerateGetterSetter_pointerToNonConst()
{
TestCase data("\n"
"class Something\n"
......@@ -363,12 +363,12 @@ void CppPlugin::test_quickfix_GetterSetter_pointerToNonConst()
"\n"
;
GetterSetter factory(/*testMode=*/ true);
GenerateGetterSetter factory(/*testMode=*/ true);
data.run(&factory, expected);
}
/// Checks: No special treatment for pointer to const.
void CppPlugin::test_quickfix_GetterSetter_pointerToConst()
void CppPlugin::test_quickfix_GenerateGetterSetter_pointerToConst()
{
TestCase data("\n"
"class Something\n"
......@@ -398,14 +398,14 @@ void CppPlugin::test_quickfix_GetterSetter_pointerToConst()
"\n"
;
GetterSetter factory(/*testMode=*/ true);
GenerateGetterSetter factory(/*testMode=*/ true);
data.run(&factory, expected);
}
/// Checks:
/// 1. Setter: Setter is a static function.
/// 2. Getter: Getter is a static, non const function.
void CppPlugin::test_quickfix_GetterSetter_staticMember()
void CppPlugin::test_quickfix_GenerateGetterSetter_staticMember()
{
TestCase data("\n"
"class Something\n"
......@@ -435,12 +435,12 @@ void CppPlugin::test_quickfix_GetterSetter_staticMember()
"\n"
;
GetterSetter factory(/*testMode=*/ true);
GenerateGetterSetter factory(/*testMode=*/ true);
data.run(&factory, expected);
}
/// Check: Check if it works on the second declarator
void CppPlugin::test_quickfix_GetterSetter_secondDeclarator()
void CppPlugin::test_quickfix_GenerateGetterSetter_secondDeclarator()
{
TestCase data("\n"
"class Something\n"
......@@ -470,12 +470,12 @@ void CppPlugin::test_quickfix_GetterSetter_secondDeclarator()
"\n"
;
GetterSetter factory(/*testMode=*/ true);
GenerateGetterSetter factory(/*testMode=*/ true);
data.run(&factory, expected);
}
/// Check: Quick fix is offered for "int *@it;" ('@' denotes the text cursor position)
void CppPlugin::test_quickfix_GetterSetter_triggeringRightAfterPointerSign()
void CppPlugin::test_quickfix_GenerateGetterSetter_triggeringRightAfterPointerSign()
{
TestCase data("\n"
"class Something\n"
......@@ -505,33 +505,33 @@ void CppPlugin::test_quickfix_GetterSetter_triggeringRightAfterPointerSign()
"\n"
;
GetterSetter factory(/*testMode=*/ true);
GenerateGetterSetter factory(/*testMode=*/ true);
data.run(&factory, expected);
}
/// Check: Quick fix is not triggered on a member function.
void CppPlugin::test_quickfix_GetterSetter_notTriggeringOnMemberFunction()
void CppPlugin::test_quickfix_GenerateGetterSetter_notTriggeringOnMemberFunction()
{
TestCase data("class Something { void @f(); };");
QByteArray expected = data.originalText;
GetterSetter factory(/*testMode=*/ true);
GenerateGetterSetter factory(/*testMode=*/ true);
data.run(&factory, expected, /*changesExpected=*/ false);
}
/// Check: Quick fix is not triggered on an member array;
void CppPlugin::test_quickfix_GetterSetter_notTriggeringOnMemberArray()
void CppPlugin::test_quickfix_GenerateGetterSetter_notTriggeringOnMemberArray()
{
TestCase data("class Something { void @a[10]; };");
QByteArray expected = data.originalText;
GetterSetter factory(/*testMode=*/ true);
GenerateGetterSetter factory(/*testMode=*/ true);
data.run(&factory, expected, /*changesExpected=*/ false);
}
/// Check: Do not offer the quick fix if there is already a member with the
/// getter or setter name we would generate.
void CppPlugin::test_quickfix_GetterSetter_notTriggeringWhenGetterOrSetterExist()
void CppPlugin::test_quickfix_GenerateGetterSetter_notTriggeringWhenGetterOrSetterExist()
{
TestCase data("\n"
"class Something {\n"
......@@ -540,6 +540,6 @@ void CppPlugin::test_quickfix_GetterSetter_notTriggeringWhenGetterOrSetterExist(
"};\n");
QByteArray expected = data.originalText;
GetterSetter factory(/*testMode=*/ true);
GenerateGetterSetter factory(/*testMode=*/ true);
data.run(&factory, expected, /*changesExpected=*/ false);
}
This source diff could not be displayed because it is too large. You can view the blob instead.
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef CPPQUICKFIXES_H
#define CPPQUICKFIXES_H
#include "cppquickfix.h"
#include <cpptools/cpprefactoringchanges.h>
#include <extensionsystem/iplugin.h>
#include <AST.h>
#include <ASTMatcher.h>
QT_BEGIN_NAMESPACE
class QByteArray;
class QString;
template <class> class QList;
QT_END_NAMESPACE
using namespace CppTools;
using namespace CPlusPlus;
using namespace TextEditor;
namespace CppEditor {
namespace Internal {
void registerQuickFixes(ExtensionSystem::IPlugin *plugIn);
/*!
Adds an include for an undefined identifier.
Activates on: the undefined identifier
*/
class AddIncludeForUndefinedIdentifier : public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
/*!
Can be triggered on a class forward declaration to add the matching #include.
Activates on: the name of a forward-declared class or struct
*/
class AddIncludeForForwardDeclaration: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
/*!
Rewrite
a op b
As
b flipop a
Activates on: <= < > >= == != && ||
*/
class FlipLogicalOperands: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
/*!
Rewrite
a op b -> !(a invop b)
(a op b) -> !(a invop b)
!(a op b) -> (a invob b)
Activates on: <= < > >= == !=
*/
class InverseLogicalComparison: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
/*!
Rewrite
!a && !b
As
!(a || b)
Activates on: &&
*/
class RewriteLogicalAnd: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
private:
ASTMatcher matcher;
};
/*!
Replace
"abcd"
QLatin1String("abcd")
QLatin1Literal("abcd")
With
@"abcd"
Activates on: the string literal, if the file type is a Objective-C(++) file.
*/
class ConvertCStringToNSString: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
/*!
Base class for converting numeric literals between decimal, octal and hex.
Does the base check for the specific ones and parses the number.
Test cases:
0xFA0Bu;
0X856A;
298.3;
199;
074;
199L;
074L;
-199;
-017;
0783; // invalid octal
0; // border case, allow only hex<->decimal
Activates on: numeric literals
*/
class ConvertNumericLiteral: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
/*!
Replace
"abcd"
With
tr("abcd") or
QCoreApplication::translate("CONTEXT", "abcd") or
QT_TRANSLATE_NOOP("GLOBAL", "abcd")
depending on what is available.
Activates on: the string literal
*/
class TranslateStringLiteral: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
/*!
Replace
"abcd" -> QLatin1String("abcd")
@"abcd" -> QLatin1String("abcd") (Objective C)
'a' -> QLatin1Char('a')
'a' -> "a"
"a" -> 'a' or QLatin1Char('a') (Single character string constants)
"\n" -> '\n', QLatin1Char('\n')
Except if they are already enclosed in
QLatin1Char, QT_TRANSLATE_NOOP, tr,
trUtf8, QLatin1Literal, QLatin1String
Activates on: the string or character literal
*/
class WrapStringLiteral: public CppQuickFixFactory
{
public:
enum ActionFlags {
EncloseInQLatin1CharAction = 0x1,
EncloseInQLatin1StringAction = 0x2,
EncloseInQStringLiteralAction = 0x4,
EncloseActionMask = EncloseInQLatin1CharAction
| EncloseInQLatin1StringAction | EncloseInQStringLiteralAction,
TranslateTrAction = 0x8,
TranslateQCoreApplicationAction = 0x10,
TranslateNoopAction = 0x20,
TranslationMask = TranslateTrAction
| TranslateQCoreApplicationAction | TranslateNoopAction,
RemoveObjectiveCAction = 0x40,
ConvertEscapeSequencesToCharAction = 0x100,
ConvertEscapeSequencesToStringAction = 0x200,
SingleQuoteAction = 0x400,
DoubleQuoteAction = 0x800
};
enum Type { TypeString, TypeObjCString, TypeChar, TypeNone };
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
static QString replacement(unsigned actions);
static QByteArray stringToCharEscapeSequences(const QByteArray &content);
static QByteArray charToStringEscapeSequences(const QByteArray &content);
static ExpressionAST *analyze(const QList<AST *> &path, const CppRefactoringFilePtr &file,
Type *type,
QByteArray *enclosingFunction = 0,
CallAST **enclosingFunctionCall = 0);
};
/*!
Turns "an_example_symbol" into "anExampleSymbol" and
"AN_EXAMPLE_SYMBOL" into "AnExampleSymbol".
Activates on: identifiers
*/
class ConvertToCamelCase : public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
/*!
Replace
if (Type name = foo()) {...}
With
Type name = foo;
if (name) {...}
Activates on: the name of the introduced variable
*/
class MoveDeclarationOutOfIf: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
/*!
Replace
while (Type name = foo()) {...}
With
Type name;
while ((name = foo()) != 0) {...}
Activates on: the name of the introduced variable
*/
class MoveDeclarationOutOfWhile: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
/*!
Replace
if (something && something_else) {
}
with
if (something)
if (something_else)
}
and
if (something || something_else)
x;
with
if (something)
x;
else if (something_else)
x;
Activates on: && or ||
*/
class SplitIfStatement: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
/*!
Rewrite
int *a, b;
As
int *a;
int b;
Activates on: the type or the variable names.
*/
class SplitSimpleDeclaration: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
private:
static bool checkDeclaration(SimpleDeclarationAST *declaration);
};
/*!
Rewrites
a = foo();
As
Type a = foo();
Where Type is the return type of foo()
Activates on: the assignee, if the type of the right-hand side of the assignment is known.
*/
class AddLocalDeclaration: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
/*!
Add curly braces to a if statement that doesn't already contain a
compound statement. I.e.
if (a)
b;
becomes
if (a)
b;
Activates on: the if
*/
class AddBracesToIf: public CppQuickFixFactory
{
public:
void match(const CppQuickFixInterface &interface, QuickFixOperations &result);
};
/*!
Switches places of the parameter declaration under cursor
with the next or the previous one in the parameter declaration list
Activates on: parameter declarations