2010-07-26 13:06:33 +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.
|
|
|
|
|
**
|
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "cppeditor.h"
|
|
|
|
|
#include "cppquickfix.h"
|
2010-09-02 15:17:57 +02:00
|
|
|
#include "cppinsertdecldef.h"
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
#include <ASTVisitor.h>
|
|
|
|
|
#include <AST.h>
|
|
|
|
|
#include <ASTMatcher.h>
|
|
|
|
|
#include <ASTPatternBuilder.h>
|
|
|
|
|
#include <CoreTypes.h>
|
|
|
|
|
#include <Literals.h>
|
|
|
|
|
#include <Name.h>
|
|
|
|
|
#include <Names.h>
|
|
|
|
|
#include <Symbol.h>
|
|
|
|
|
#include <Symbols.h>
|
|
|
|
|
#include <Token.h>
|
|
|
|
|
#include <TranslationUnit.h>
|
|
|
|
|
#include <Type.h>
|
|
|
|
|
|
|
|
|
|
#include <cplusplus/DependencyTable.h>
|
|
|
|
|
#include <cplusplus/Overview.h>
|
|
|
|
|
#include <cplusplus/TypeOfExpression.h>
|
|
|
|
|
#include <cplusplus/CppRewriter.h>
|
|
|
|
|
#include <cpptools/cpptoolsconstants.h>
|
|
|
|
|
#include <extensionsystem/iplugin.h>
|
|
|
|
|
|
|
|
|
|
#include <QtGui/QApplication>
|
|
|
|
|
#include <QtGui/QTextBlock>
|
|
|
|
|
#include <QtGui/QTextCursor>
|
|
|
|
|
|
|
|
|
|
using namespace CppEditor;
|
|
|
|
|
using namespace CppEditor::Internal;
|
2010-09-30 12:09:38 +02:00
|
|
|
using namespace CppTools;
|
2010-07-26 13:06:33 +02:00
|
|
|
using namespace TextEditor;
|
|
|
|
|
using namespace CPlusPlus;
|
|
|
|
|
using namespace Utils;
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Rewrite
|
|
|
|
|
a op b -> !(a invop b)
|
|
|
|
|
(a op b) -> !(a invop b)
|
|
|
|
|
!(a op b) -> (a invob b)
|
|
|
|
|
*/
|
|
|
|
|
class UseInverseOp: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
QList<CppQuickFixOperation::Ptr> result;
|
2010-08-13 12:49:11 +02:00
|
|
|
const CppRefactoringFile &file = state.currentFile();
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
const QList<AST *> &path = state.path();
|
|
|
|
|
int index = path.size() - 1;
|
|
|
|
|
BinaryExpressionAST *binary = path.at(index)->asBinaryExpression();
|
|
|
|
|
if (! binary)
|
|
|
|
|
return result;
|
|
|
|
|
if (! state.isCursorOn(binary->binary_op_token))
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
Kind invertToken;
|
2010-08-13 12:49:11 +02:00
|
|
|
switch (file.tokenAt(binary->binary_op_token).kind()) {
|
2010-07-26 13:06:33 +02:00
|
|
|
case T_LESS_EQUAL:
|
|
|
|
|
invertToken = T_GREATER;
|
|
|
|
|
break;
|
|
|
|
|
case T_LESS:
|
|
|
|
|
invertToken = T_GREATER_EQUAL;
|
|
|
|
|
break;
|
|
|
|
|
case T_GREATER:
|
|
|
|
|
invertToken = T_LESS_EQUAL;
|
|
|
|
|
break;
|
|
|
|
|
case T_GREATER_EQUAL:
|
|
|
|
|
invertToken = T_LESS;
|
|
|
|
|
break;
|
|
|
|
|
case T_EQUAL_EQUAL:
|
|
|
|
|
invertToken = T_EXCLAIM_EQUAL;
|
|
|
|
|
break;
|
|
|
|
|
case T_EXCLAIM_EQUAL:
|
|
|
|
|
invertToken = T_EQUAL_EQUAL;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.append(CppQuickFixOperation::Ptr(new Operation(state, index, binary, invertToken)));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
BinaryExpressionAST *binary;
|
|
|
|
|
NestedExpressionAST *nested;
|
|
|
|
|
UnaryExpressionAST *negation;
|
|
|
|
|
|
|
|
|
|
QString replacement;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state, int priority, BinaryExpressionAST *binary, Kind invertToken)
|
|
|
|
|
: CppQuickFixOperation(state, priority)
|
|
|
|
|
, binary(binary)
|
|
|
|
|
{
|
|
|
|
|
Token tok;
|
|
|
|
|
tok.f.kind = invertToken;
|
|
|
|
|
replacement = QLatin1String(tok.spell());
|
|
|
|
|
|
|
|
|
|
// check for enclosing nested expression
|
|
|
|
|
if (priority - 1 >= 0)
|
|
|
|
|
nested = state.path()[priority - 1]->asNestedExpression();
|
|
|
|
|
|
|
|
|
|
// check for ! before parentheses
|
|
|
|
|
if (nested && priority - 2 >= 0) {
|
|
|
|
|
negation = state.path()[priority - 2]->asUnaryExpression();
|
2010-08-13 12:49:11 +02:00
|
|
|
if (negation && ! state.currentFile().tokenAt(negation->unary_op_token).is(T_EXCLAIM))
|
2010-07-26 13:06:33 +02:00
|
|
|
negation = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual QString description() const
|
|
|
|
|
{
|
|
|
|
|
return QApplication::translate("CppTools::QuickFix", "Rewrite Using %1").arg(replacement);
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
|
|
|
|
if (negation) {
|
|
|
|
|
// can't remove parentheses since that might break precedence
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.remove(currentFile->range(negation->unary_op_token));
|
2010-07-26 13:06:33 +02:00
|
|
|
} else if (nested) {
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.insert(currentFile->startOf(nested), "!");
|
2010-07-26 13:06:33 +02:00
|
|
|
} else {
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.insert(currentFile->startOf(binary), "!(");
|
|
|
|
|
changes.insert(currentFile->endOf(binary), ")");
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.replace(currentFile->range(binary->binary_op_token), replacement);
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Rewrite
|
|
|
|
|
a op b
|
|
|
|
|
|
|
|
|
|
As
|
|
|
|
|
b flipop a
|
|
|
|
|
*/
|
|
|
|
|
class FlipBinaryOp: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<QuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
QList<QuickFixOperation::Ptr> result;
|
|
|
|
|
const QList<AST *> &path = state.path();
|
2010-08-13 12:49:11 +02:00
|
|
|
const CppRefactoringFile &file = state.currentFile();
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
int index = path.size() - 1;
|
|
|
|
|
BinaryExpressionAST *binary = path.at(index)->asBinaryExpression();
|
|
|
|
|
if (! binary)
|
|
|
|
|
return result;
|
|
|
|
|
if (! state.isCursorOn(binary->binary_op_token))
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
Kind flipToken;
|
2010-08-13 12:49:11 +02:00
|
|
|
switch (file.tokenAt(binary->binary_op_token).kind()) {
|
2010-07-26 13:06:33 +02:00
|
|
|
case T_LESS_EQUAL:
|
|
|
|
|
flipToken = T_GREATER_EQUAL;
|
|
|
|
|
break;
|
|
|
|
|
case T_LESS:
|
|
|
|
|
flipToken = T_GREATER;
|
|
|
|
|
break;
|
|
|
|
|
case T_GREATER:
|
|
|
|
|
flipToken = T_LESS;
|
|
|
|
|
break;
|
|
|
|
|
case T_GREATER_EQUAL:
|
|
|
|
|
flipToken = T_LESS_EQUAL;
|
|
|
|
|
break;
|
|
|
|
|
case T_EQUAL_EQUAL:
|
|
|
|
|
case T_EXCLAIM_EQUAL:
|
|
|
|
|
case T_AMPER_AMPER:
|
|
|
|
|
case T_PIPE_PIPE:
|
|
|
|
|
flipToken = T_EOF_SYMBOL;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString replacement;
|
|
|
|
|
if (flipToken != T_EOF_SYMBOL) {
|
|
|
|
|
Token tok;
|
|
|
|
|
tok.f.kind = flipToken;
|
|
|
|
|
replacement = QLatin1String(tok.spell());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result.append(QuickFixOperation::Ptr(new Operation(state, index, binary, replacement)));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state, int priority, BinaryExpressionAST *binary, QString replacement)
|
|
|
|
|
: CppQuickFixOperation(state)
|
|
|
|
|
, binary(binary)
|
|
|
|
|
, replacement(replacement)
|
|
|
|
|
{
|
|
|
|
|
setPriority(priority);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual QString description() const
|
|
|
|
|
{
|
|
|
|
|
if (replacement.isEmpty())
|
|
|
|
|
return QApplication::translate("CppTools::QuickFix", "Swap Operands");
|
|
|
|
|
else
|
|
|
|
|
return QApplication::translate("CppTools::QuickFix", "Rewrite Using %1").arg(replacement);
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.flip(currentFile->range(binary->left_expression), currentFile->range(binary->right_expression));
|
2010-07-26 13:06:33 +02:00
|
|
|
if (! replacement.isEmpty())
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.replace(currentFile->range(binary->binary_op_token), replacement);
|
2010-07-26 13:06:33 +02:00
|
|
|
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
BinaryExpressionAST *binary;
|
|
|
|
|
QString replacement;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Rewrite
|
|
|
|
|
!a && !b
|
|
|
|
|
|
|
|
|
|
As
|
|
|
|
|
!(a || b)
|
|
|
|
|
*/
|
|
|
|
|
class RewriteLogicalAndOp: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<QuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
QList<QuickFixOperation::Ptr> result;
|
|
|
|
|
BinaryExpressionAST *expression = 0;
|
|
|
|
|
const QList<AST *> &path = state.path();
|
2010-08-13 12:49:11 +02:00
|
|
|
const CppRefactoringFile &file = state.currentFile();
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
int index = path.size() - 1;
|
|
|
|
|
for (; index != -1; --index) {
|
|
|
|
|
expression = path.at(index)->asBinaryExpression();
|
|
|
|
|
if (expression)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! expression)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
if (! state.isCursorOn(expression->binary_op_token))
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
QSharedPointer<Operation> op(new Operation(state));
|
|
|
|
|
|
|
|
|
|
if (expression->match(op->pattern, &matcher) &&
|
2010-08-13 12:49:11 +02:00
|
|
|
file.tokenAt(op->pattern->binary_op_token).is(T_AMPER_AMPER) &&
|
|
|
|
|
file.tokenAt(op->left->unary_op_token).is(T_EXCLAIM) &&
|
|
|
|
|
file.tokenAt(op->right->unary_op_token).is(T_EXCLAIM)) {
|
2010-07-26 13:06:33 +02:00
|
|
|
op->setDescription(QApplication::translate("CppTools::QuickFix", "Rewrite Condition Using ||"));
|
|
|
|
|
op->setPriority(index);
|
|
|
|
|
result.append(op);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
QSharedPointer<ASTPatternBuilder> mk;
|
|
|
|
|
UnaryExpressionAST *left;
|
|
|
|
|
UnaryExpressionAST *right;
|
|
|
|
|
BinaryExpressionAST *pattern;
|
|
|
|
|
|
|
|
|
|
Operation(const CppQuickFixState &state)
|
|
|
|
|
: CppQuickFixOperation(state)
|
|
|
|
|
, mk(new ASTPatternBuilder)
|
|
|
|
|
{
|
|
|
|
|
left = mk->UnaryExpression();
|
|
|
|
|
right = mk->UnaryExpression();
|
|
|
|
|
pattern = mk->BinaryExpression(left, right);
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.replace(currentFile->range(pattern->binary_op_token), QLatin1String("||"));
|
|
|
|
|
changes.remove(currentFile->range(left->unary_op_token));
|
|
|
|
|
changes.remove(currentFile->range(right->unary_op_token));
|
|
|
|
|
const int start = currentFile->startOf(pattern);
|
|
|
|
|
const int end = currentFile->endOf(pattern);
|
2010-07-26 13:06:33 +02:00
|
|
|
changes.insert(start, QLatin1String("!("));
|
|
|
|
|
changes.insert(end, QLatin1String(")"));
|
|
|
|
|
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-08-13 12:49:11 +02:00
|
|
|
currentFile->indent(currentFile->range(pattern));
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
ASTMatcher matcher;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class SplitSimpleDeclarationOp: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
static bool checkDeclaration(SimpleDeclarationAST *declaration)
|
|
|
|
|
{
|
|
|
|
|
if (! declaration->semicolon_token)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (! declaration->decl_specifier_list)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
for (SpecifierListAST *it = declaration->decl_specifier_list; it; it = it->next) {
|
|
|
|
|
SpecifierAST *specifier = it->value;
|
|
|
|
|
|
|
|
|
|
if (specifier->asEnumSpecifier() != 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
else if (specifier->asClassSpecifier() != 0)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! declaration->declarator_list)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
else if (! declaration->declarator_list->next)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
QList<CppQuickFixOperation::Ptr> result;
|
|
|
|
|
CoreDeclaratorAST *core_declarator = 0;
|
|
|
|
|
const QList<AST *> &path = state.path();
|
2010-08-13 12:49:11 +02:00
|
|
|
const CppRefactoringFile &file = state.currentFile();
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
for (int index = path.size() - 1; index != -1; --index) {
|
|
|
|
|
AST *node = path.at(index);
|
|
|
|
|
|
|
|
|
|
if (CoreDeclaratorAST *coreDecl = node->asCoreDeclarator())
|
|
|
|
|
core_declarator = coreDecl;
|
|
|
|
|
|
|
|
|
|
else if (SimpleDeclarationAST *simpleDecl = node->asSimpleDeclaration()) {
|
|
|
|
|
if (checkDeclaration(simpleDecl)) {
|
|
|
|
|
SimpleDeclarationAST *declaration = simpleDecl;
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
const int cursorPosition = file.cursor().selectionStart();
|
2010-07-26 13:06:33 +02:00
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
const int startOfDeclSpecifier = file.startOf(declaration->decl_specifier_list->firstToken());
|
|
|
|
|
const int endOfDeclSpecifier = file.endOf(declaration->decl_specifier_list->lastToken() - 1);
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
if (cursorPosition >= startOfDeclSpecifier && cursorPosition <= endOfDeclSpecifier) {
|
|
|
|
|
// the AST node under cursor is a specifier.
|
|
|
|
|
return singleResult(new Operation(state, index, declaration));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (core_declarator && state.isCursorOn(core_declarator)) {
|
|
|
|
|
// got a core-declarator under the text cursor.
|
|
|
|
|
return singleResult(new Operation(state, index, declaration));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state, int priority, SimpleDeclarationAST *decl)
|
|
|
|
|
: CppQuickFixOperation(state, priority)
|
|
|
|
|
, declaration(decl)
|
|
|
|
|
{
|
|
|
|
|
setDescription(QApplication::translate("CppTools::QuickFix",
|
|
|
|
|
"Split Declaration"));
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
|
|
|
|
|
|
|
|
|
SpecifierListAST *specifiers = declaration->decl_specifier_list;
|
2010-08-13 12:49:11 +02:00
|
|
|
int declSpecifiersStart = currentFile->startOf(specifiers->firstToken());
|
|
|
|
|
int declSpecifiersEnd = currentFile->endOf(specifiers->lastToken() - 1);
|
|
|
|
|
int insertPos = currentFile->endOf(declaration->semicolon_token);
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
DeclaratorAST *prevDeclarator = declaration->declarator_list->value;
|
|
|
|
|
|
|
|
|
|
for (DeclaratorListAST *it = declaration->declarator_list->next; it; it = it->next) {
|
|
|
|
|
DeclaratorAST *declarator = it->value;
|
|
|
|
|
|
|
|
|
|
changes.insert(insertPos, QLatin1String("\n"));
|
|
|
|
|
changes.copy(declSpecifiersStart, declSpecifiersEnd, insertPos);
|
|
|
|
|
changes.insert(insertPos, QLatin1String(" "));
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.move(currentFile->range(declarator), insertPos);
|
2010-07-26 13:06:33 +02:00
|
|
|
changes.insert(insertPos, QLatin1String(";"));
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
const int prevDeclEnd = currentFile->endOf(prevDeclarator);
|
|
|
|
|
changes.remove(prevDeclEnd, currentFile->startOf(declarator));
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
prevDeclarator = declarator;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-08-13 12:49:11 +02:00
|
|
|
currentFile->indent(currentFile->range(declaration));
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
SimpleDeclarationAST *declaration;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Add curly braces to a if statement that doesn't already contain a
|
|
|
|
|
compound statement.
|
|
|
|
|
*/
|
|
|
|
|
class AddBracesToIfOp: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
const QList<AST *> &path = state.path();
|
|
|
|
|
|
|
|
|
|
// show when we're on the 'if' of an if statement
|
|
|
|
|
int index = path.size() - 1;
|
|
|
|
|
IfStatementAST *ifStatement = path.at(index)->asIfStatement();
|
|
|
|
|
if (ifStatement && state.isCursorOn(ifStatement->if_token) && ifStatement->statement
|
|
|
|
|
&& ! ifStatement->statement->asCompoundStatement()) {
|
|
|
|
|
return singleResult(new Operation(state, index, ifStatement->statement));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// or if we're on the statement contained in the if
|
|
|
|
|
// ### This may not be such a good idea, consider nested ifs...
|
|
|
|
|
for (; index != -1; --index) {
|
|
|
|
|
IfStatementAST *ifStatement = path.at(index)->asIfStatement();
|
|
|
|
|
if (ifStatement && ifStatement->statement
|
|
|
|
|
&& state.isCursorOn(ifStatement->statement)
|
|
|
|
|
&& ! ifStatement->statement->asCompoundStatement()) {
|
|
|
|
|
return singleResult(new Operation(state, index, ifStatement->statement));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ### This could very well be extended to the else branch
|
|
|
|
|
// and other nodes entirely.
|
|
|
|
|
|
|
|
|
|
return noResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state, int priority, StatementAST *statement)
|
|
|
|
|
: CppQuickFixOperation(state, priority)
|
|
|
|
|
, _statement(statement)
|
|
|
|
|
{
|
|
|
|
|
setDescription(QApplication::translate("CppTools::QuickFix",
|
|
|
|
|
"Add Curly Braces"));
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
const int start = currentFile->endOf(_statement->firstToken() - 1);
|
2010-07-26 13:06:33 +02:00
|
|
|
changes.insert(start, QLatin1String(" {"));
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
const int end = currentFile->endOf(_statement->lastToken() - 1);
|
2010-07-26 13:06:33 +02:00
|
|
|
changes.insert(end, "\n}");
|
|
|
|
|
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-08-13 12:49:11 +02:00
|
|
|
currentFile->indent(Range(start, end));
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
StatementAST *_statement;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Replace
|
|
|
|
|
if (Type name = foo()) {...}
|
|
|
|
|
|
|
|
|
|
With
|
|
|
|
|
Type name = foo;
|
|
|
|
|
if (name) {...}
|
|
|
|
|
*/
|
|
|
|
|
class MoveDeclarationOutOfIfOp: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
const QList<AST *> &path = state.path();
|
|
|
|
|
QSharedPointer<Operation> op(new Operation(state));
|
|
|
|
|
|
|
|
|
|
int index = path.size() - 1;
|
|
|
|
|
for (; index != -1; --index) {
|
|
|
|
|
if (IfStatementAST *statement = path.at(index)->asIfStatement()) {
|
|
|
|
|
if (statement->match(op->pattern, &op->matcher) && op->condition->declarator) {
|
|
|
|
|
DeclaratorAST *declarator = op->condition->declarator;
|
|
|
|
|
op->core = declarator->core_declarator;
|
|
|
|
|
if (! op->core)
|
|
|
|
|
return noResult();
|
|
|
|
|
|
|
|
|
|
if (state.isCursorOn(op->core)) {
|
|
|
|
|
QList<CppQuickFixOperation::Ptr> result;
|
|
|
|
|
op->setPriority(index);
|
|
|
|
|
result.append(op);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return noResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state)
|
|
|
|
|
: CppQuickFixOperation(state)
|
|
|
|
|
{
|
|
|
|
|
setDescription(QApplication::translate("CppTools::QuickFix",
|
|
|
|
|
"Move Declaration out of Condition"));
|
|
|
|
|
|
|
|
|
|
condition = mk.Condition();
|
|
|
|
|
pattern = mk.IfStatement(condition);
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.copy(currentFile->range(core), currentFile->startOf(condition));
|
2010-07-26 13:06:33 +02:00
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
int insertPos = currentFile->startOf(pattern);
|
|
|
|
|
changes.move(currentFile->range(condition), insertPos);
|
2010-07-26 13:06:33 +02:00
|
|
|
changes.insert(insertPos, QLatin1String(";\n"));
|
|
|
|
|
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-08-13 12:49:11 +02:00
|
|
|
currentFile->indent(currentFile->range(pattern));
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ASTMatcher matcher;
|
|
|
|
|
ASTPatternBuilder mk;
|
|
|
|
|
CPPEditor *editor;
|
|
|
|
|
ConditionAST *condition;
|
|
|
|
|
IfStatementAST *pattern;
|
|
|
|
|
CoreDeclaratorAST *core;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Replace
|
|
|
|
|
while (Type name = foo()) {...}
|
|
|
|
|
|
|
|
|
|
With
|
|
|
|
|
Type name;
|
|
|
|
|
while ((name = foo()) != 0) {...}
|
|
|
|
|
*/
|
|
|
|
|
class MoveDeclarationOutOfWhileOp: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
const QList<AST *> &path = state.path();
|
|
|
|
|
QSharedPointer<Operation> op(new Operation(state));
|
|
|
|
|
|
|
|
|
|
int index = path.size() - 1;
|
|
|
|
|
for (; index != -1; --index) {
|
|
|
|
|
if (WhileStatementAST *statement = path.at(index)->asWhileStatement()) {
|
|
|
|
|
if (statement->match(op->pattern, &op->matcher) && op->condition->declarator) {
|
|
|
|
|
DeclaratorAST *declarator = op->condition->declarator;
|
|
|
|
|
op->core = declarator->core_declarator;
|
|
|
|
|
|
|
|
|
|
if (! op->core)
|
|
|
|
|
return noResult();
|
|
|
|
|
|
2010-08-16 11:38:34 +02:00
|
|
|
else if (! declarator->equal_token)
|
2010-07-26 13:06:33 +02:00
|
|
|
return noResult();
|
|
|
|
|
|
|
|
|
|
else if (! declarator->initializer)
|
|
|
|
|
return noResult();
|
|
|
|
|
|
|
|
|
|
if (state.isCursorOn(op->core)) {
|
|
|
|
|
QList<CppQuickFixOperation::Ptr> result;
|
|
|
|
|
op->setPriority(index);
|
|
|
|
|
result.append(op);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return noResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state)
|
|
|
|
|
: CppQuickFixOperation(state)
|
|
|
|
|
{
|
|
|
|
|
setDescription(QApplication::translate("CppTools::QuickFix",
|
|
|
|
|
"Move Declaration out of Condition"));
|
|
|
|
|
|
|
|
|
|
condition = mk.Condition();
|
|
|
|
|
pattern = mk.WhileStatement(condition);
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.insert(currentFile->startOf(condition), QLatin1String("("));
|
|
|
|
|
changes.insert(currentFile->endOf(condition), QLatin1String(") != 0"));
|
2010-07-26 13:06:33 +02:00
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
int insertPos = currentFile->startOf(pattern);
|
|
|
|
|
const int conditionStart = currentFile->startOf(condition);
|
|
|
|
|
changes.move(conditionStart, currentFile->startOf(core), insertPos);
|
|
|
|
|
changes.copy(currentFile->range(core), insertPos);
|
2010-07-26 13:06:33 +02:00
|
|
|
changes.insert(insertPos, QLatin1String(";\n"));
|
|
|
|
|
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-08-13 12:49:11 +02:00
|
|
|
currentFile->indent(currentFile->range(pattern));
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ASTMatcher matcher;
|
|
|
|
|
ASTPatternBuilder mk;
|
|
|
|
|
CPPEditor *editor;
|
|
|
|
|
ConditionAST *condition;
|
|
|
|
|
WhileStatementAST *pattern;
|
|
|
|
|
CoreDeclaratorAST *core;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
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;
|
|
|
|
|
*/
|
|
|
|
|
class SplitIfStatementOp: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
IfStatementAST *pattern = 0;
|
|
|
|
|
const QList<AST *> &path = state.path();
|
|
|
|
|
|
|
|
|
|
int index = path.size() - 1;
|
|
|
|
|
for (; index != -1; --index) {
|
|
|
|
|
AST *node = path.at(index);
|
|
|
|
|
if (IfStatementAST *stmt = node->asIfStatement()) {
|
|
|
|
|
pattern = stmt;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! pattern || ! pattern->statement)
|
|
|
|
|
return noResult();
|
|
|
|
|
|
|
|
|
|
unsigned splitKind = 0;
|
|
|
|
|
for (++index; index < path.size(); ++index) {
|
|
|
|
|
AST *node = path.at(index);
|
|
|
|
|
BinaryExpressionAST *condition = node->asBinaryExpression();
|
|
|
|
|
if (! condition)
|
|
|
|
|
return noResult();
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
Token binaryToken = state.currentFile().tokenAt(condition->binary_op_token);
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
// only accept a chain of ||s or &&s - no mixing
|
|
|
|
|
if (! splitKind) {
|
|
|
|
|
splitKind = binaryToken.kind();
|
|
|
|
|
if (splitKind != T_AMPER_AMPER && splitKind != T_PIPE_PIPE)
|
|
|
|
|
return noResult();
|
|
|
|
|
// we can't reliably split &&s in ifs with an else branch
|
|
|
|
|
if (splitKind == T_AMPER_AMPER && pattern->else_statement)
|
|
|
|
|
return noResult();
|
|
|
|
|
} else if (splitKind != binaryToken.kind()) {
|
|
|
|
|
return noResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state.isCursorOn(condition->binary_op_token))
|
|
|
|
|
return singleResult(new Operation(state, index, pattern, condition));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return noResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state, int priority,
|
|
|
|
|
IfStatementAST *pattern, BinaryExpressionAST *condition)
|
|
|
|
|
: CppQuickFixOperation(state, priority)
|
|
|
|
|
, pattern(pattern)
|
|
|
|
|
, condition(condition)
|
|
|
|
|
{
|
|
|
|
|
setDescription(QApplication::translate("CppTools::QuickFix",
|
|
|
|
|
"Split if Statement"));
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
2010-08-13 12:49:11 +02:00
|
|
|
const Token binaryToken = currentFile->tokenAt(condition->binary_op_token);
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
if (binaryToken.is(T_AMPER_AMPER))
|
2010-08-12 13:46:18 +02:00
|
|
|
splitAndCondition(currentFile);
|
2010-07-26 13:06:33 +02:00
|
|
|
else
|
2010-08-12 13:46:18 +02:00
|
|
|
splitOrCondition(currentFile);
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
void splitAndCondition(CppRefactoringFile *currentFile)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
int startPos = currentFile->startOf(pattern);
|
2010-07-26 13:06:33 +02:00
|
|
|
changes.insert(startPos, QLatin1String("if ("));
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.move(currentFile->range(condition->left_expression), startPos);
|
2010-07-26 13:06:33 +02:00
|
|
|
changes.insert(startPos, QLatin1String(") {\n"));
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
const int lExprEnd = currentFile->endOf(condition->left_expression);
|
|
|
|
|
changes.remove(lExprEnd, currentFile->startOf(condition->right_expression));
|
|
|
|
|
changes.insert(currentFile->endOf(pattern), QLatin1String("\n}"));
|
2010-07-26 13:06:33 +02:00
|
|
|
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-08-13 12:49:11 +02:00
|
|
|
currentFile->indent(currentFile->range(pattern));
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
void splitOrCondition(CppRefactoringFile *currentFile)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
|
|
|
|
|
|
|
|
|
StatementAST *ifTrueStatement = pattern->statement;
|
|
|
|
|
CompoundStatementAST *compoundStatement = ifTrueStatement->asCompoundStatement();
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
int insertPos = currentFile->endOf(ifTrueStatement);
|
2010-07-26 13:06:33 +02:00
|
|
|
if (compoundStatement)
|
|
|
|
|
changes.insert(insertPos, QLatin1String(" "));
|
|
|
|
|
else
|
|
|
|
|
changes.insert(insertPos, QLatin1String("\n"));
|
|
|
|
|
changes.insert(insertPos, QLatin1String("else if ("));
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
const int rExprStart = currentFile->startOf(condition->right_expression);
|
|
|
|
|
changes.move(rExprStart, currentFile->startOf(pattern->rparen_token), insertPos);
|
2010-07-26 13:06:33 +02:00
|
|
|
changes.insert(insertPos, QLatin1String(")"));
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
const int rParenEnd = currentFile->endOf(pattern->rparen_token);
|
|
|
|
|
changes.copy(rParenEnd, currentFile->endOf(pattern->statement), insertPos);
|
2010-07-26 13:06:33 +02:00
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
const int lExprEnd = currentFile->endOf(condition->left_expression);
|
|
|
|
|
changes.remove(lExprEnd, currentFile->startOf(condition->right_expression));
|
2010-07-26 13:06:33 +02:00
|
|
|
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-08-13 12:49:11 +02:00
|
|
|
currentFile->indent(currentFile->range(pattern));
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
IfStatementAST *pattern;
|
|
|
|
|
BinaryExpressionAST *condition;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Replace
|
|
|
|
|
"abcd"
|
|
|
|
|
With
|
|
|
|
|
QLatin1String("abcd")
|
|
|
|
|
*/
|
|
|
|
|
class WrapStringLiteral: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
enum Type { TypeString, TypeObjCString, TypeChar, TypeNone };
|
|
|
|
|
|
|
|
|
|
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
ExpressionAST *literal = 0;
|
|
|
|
|
Type type = TypeNone;
|
|
|
|
|
const QList<AST *> &path = state.path();
|
2010-08-13 12:49:11 +02:00
|
|
|
const CppRefactoringFile &file = state.currentFile();
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
if (path.isEmpty())
|
|
|
|
|
return noResult(); // nothing to do
|
|
|
|
|
|
|
|
|
|
literal = path.last()->asStringLiteral();
|
|
|
|
|
|
|
|
|
|
if (! literal) {
|
|
|
|
|
literal = path.last()->asNumericLiteral();
|
2010-08-13 12:49:11 +02:00
|
|
|
if (!literal || !file.tokenAt(literal->asNumericLiteral()->literal_token).is(T_CHAR_LITERAL))
|
2010-07-26 13:06:33 +02:00
|
|
|
return noResult();
|
|
|
|
|
else
|
|
|
|
|
type = TypeChar;
|
|
|
|
|
} else {
|
|
|
|
|
type = TypeString;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (path.size() > 1) {
|
|
|
|
|
if (CallAST *call = path.at(path.size() - 2)->asCall()) {
|
|
|
|
|
if (call->base_expression) {
|
2010-08-02 12:04:59 +02:00
|
|
|
if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) {
|
|
|
|
|
if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) {
|
2010-08-13 12:49:11 +02:00
|
|
|
const QByteArray id(file.tokenAt(functionName->identifier_token).identifier->chars());
|
2010-08-02 12:04:59 +02:00
|
|
|
|
|
|
|
|
if (id == "QT_TRANSLATE_NOOP" || id == "tr" || id == "trUtf8"
|
|
|
|
|
|| (type == TypeString && (id == "QLatin1String" || id == "QLatin1Literal"))
|
|
|
|
|
|| (type == TypeChar && id == "QLatin1Char"))
|
|
|
|
|
return noResult(); // skip it
|
|
|
|
|
}
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (type == TypeString) {
|
2010-08-13 12:49:11 +02:00
|
|
|
if (file.charAt(file.startOf(literal)) == QLatin1Char('@'))
|
2010-07-26 13:06:33 +02:00
|
|
|
type = TypeObjCString;
|
|
|
|
|
}
|
|
|
|
|
return singleResult(new Operation(state,
|
|
|
|
|
path.size() - 1, // very high priority
|
|
|
|
|
type,
|
|
|
|
|
literal));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state, int priority, Type type,
|
|
|
|
|
ExpressionAST *literal)
|
|
|
|
|
: CppQuickFixOperation(state, priority)
|
|
|
|
|
, type(type)
|
|
|
|
|
, literal(literal)
|
|
|
|
|
{
|
|
|
|
|
if (type == TypeChar)
|
|
|
|
|
setDescription(QApplication::translate("CppTools::QuickFix",
|
|
|
|
|
"Enclose in QLatin1Char(...)"));
|
|
|
|
|
else
|
|
|
|
|
setDescription(QApplication::translate("CppTools::QuickFix",
|
|
|
|
|
"Enclose in QLatin1String(...)"));
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
const int startPos = currentFile->startOf(literal);
|
2010-07-26 13:06:33 +02:00
|
|
|
QLatin1String replacement = (type == TypeChar ? QLatin1String("QLatin1Char(")
|
|
|
|
|
: QLatin1String("QLatin1String("));
|
|
|
|
|
|
|
|
|
|
if (type == TypeObjCString)
|
|
|
|
|
changes.replace(startPos, startPos + 1, replacement);
|
|
|
|
|
else
|
|
|
|
|
changes.insert(startPos, replacement);
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.insert(currentFile->endOf(literal), ")");
|
2010-07-26 13:06:33 +02:00
|
|
|
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Type type;
|
|
|
|
|
ExpressionAST *literal;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Replace
|
|
|
|
|
"abcd"
|
|
|
|
|
With
|
|
|
|
|
tr("abcd") or
|
|
|
|
|
QCoreApplication::translate("CONTEXT", "abcd") or
|
|
|
|
|
QT_TRANSLATE_NOOP("GLOBAL", "abcd")
|
|
|
|
|
*/
|
|
|
|
|
class TranslateStringLiteral: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
enum TranslationOption { unknown, useTr, useQCoreApplicationTranslate, useMacro };
|
|
|
|
|
|
|
|
|
|
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
const QList<AST *> &path = state.path();
|
|
|
|
|
// Initialize
|
|
|
|
|
ExpressionAST *literal = 0;
|
|
|
|
|
QString trContext;
|
|
|
|
|
|
|
|
|
|
if (path.isEmpty())
|
|
|
|
|
return noResult();
|
|
|
|
|
|
|
|
|
|
literal = path.last()->asStringLiteral();
|
|
|
|
|
if (!literal)
|
|
|
|
|
return noResult(); // No string, nothing to do
|
|
|
|
|
|
|
|
|
|
// Do we already have a translation markup?
|
|
|
|
|
if (path.size() >= 2) {
|
|
|
|
|
if (CallAST *call = path.at(path.size() - 2)->asCall()) {
|
|
|
|
|
if (call->base_expression) {
|
2010-08-02 12:04:59 +02:00
|
|
|
if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) {
|
|
|
|
|
if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) {
|
2010-08-13 12:49:11 +02:00
|
|
|
const QByteArray id(state.currentFile().tokenAt(functionName->identifier_token).identifier->chars());
|
2010-08-02 12:04:59 +02:00
|
|
|
|
|
|
|
|
if (id == "tr" || id == "trUtf8"
|
|
|
|
|
|| id == "translate"
|
|
|
|
|
|| id == "QT_TRANSLATE_NOOP"
|
|
|
|
|
|| id == "QLatin1String" || id == "QLatin1Literal")
|
|
|
|
|
return noResult(); // skip it
|
|
|
|
|
}
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QSharedPointer<Control> control = state.context().control();
|
2010-09-02 11:59:01 +02:00
|
|
|
const Name *trName = control->identifier("tr");
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
// Check whether we are in a method:
|
|
|
|
|
for (int i = path.size() - 1; i >= 0; --i)
|
|
|
|
|
{
|
|
|
|
|
if (FunctionDefinitionAST *definition = path.at(i)->asFunctionDefinition()) {
|
|
|
|
|
Function *function = definition->symbol;
|
|
|
|
|
ClassOrNamespace *b = state.context().lookupType(function);
|
|
|
|
|
if (b) {
|
|
|
|
|
// Do we have a tr method?
|
|
|
|
|
foreach(const LookupItem &r, b->find(trName)) {
|
|
|
|
|
Symbol *s = r.declaration();
|
|
|
|
|
if (s->type()->isFunctionType()) {
|
|
|
|
|
// no context required for tr
|
|
|
|
|
return singleResult(new Operation(state, path.size() - 1, literal, useTr, trContext));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// We need to do a QCA::translate, so we need a context.
|
|
|
|
|
// Use fully qualified class name:
|
|
|
|
|
Overview oo;
|
|
|
|
|
foreach (const Name *n, LookupContext::path(function)) {
|
|
|
|
|
if (!trContext.isEmpty())
|
|
|
|
|
trContext.append(QLatin1String("::"));
|
|
|
|
|
trContext.append(oo.prettyName(n));
|
|
|
|
|
}
|
|
|
|
|
// ... or global if none available!
|
|
|
|
|
if (trContext.isEmpty())
|
|
|
|
|
trContext = QLatin1String("GLOBAL");
|
|
|
|
|
return singleResult(new Operation(state, path.size() - 1, literal, useQCoreApplicationTranslate, trContext));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We need to use Q_TRANSLATE_NOOP
|
|
|
|
|
return singleResult(new Operation(state, path.size() - 1, literal, useMacro, QLatin1String("GLOBAL")));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state, int priority, ExpressionAST *literal, TranslationOption option, const QString &context)
|
|
|
|
|
: CppQuickFixOperation(state, priority)
|
|
|
|
|
, m_literal(literal)
|
|
|
|
|
, m_option(option)
|
|
|
|
|
, m_context(context)
|
|
|
|
|
{
|
2010-10-06 16:33:49 +02:00
|
|
|
setDescription(QApplication::translate("CppTools::QuickFix", "Mark as Translatable"));
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
const int startPos = currentFile->startOf(m_literal);
|
2010-07-26 13:06:33 +02:00
|
|
|
QString replacement(QLatin1String("tr("));
|
|
|
|
|
if (m_option == useQCoreApplicationTranslate) {
|
|
|
|
|
replacement = QLatin1String("QCoreApplication::translate(\"")
|
|
|
|
|
+ m_context + QLatin1String("\", ");
|
|
|
|
|
} else if (m_option == useMacro) {
|
|
|
|
|
replacement = QLatin1String("QT_TRANSLATE_NOOP(\"")
|
|
|
|
|
+ m_context + QLatin1String("\", ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
changes.insert(startPos, replacement);
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.insert(currentFile->endOf(m_literal), QLatin1String(")"));
|
2010-07-26 13:06:33 +02:00
|
|
|
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
ExpressionAST *m_literal;
|
|
|
|
|
TranslationOption m_option;
|
|
|
|
|
QString m_context;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class CStringToNSString: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
2010-08-13 12:49:11 +02:00
|
|
|
const CppRefactoringFile &file = state.currentFile();
|
|
|
|
|
|
2010-07-26 13:06:33 +02:00
|
|
|
if (state.editor()->mimeType() != CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)
|
|
|
|
|
return noResult();
|
|
|
|
|
|
|
|
|
|
StringLiteralAST *stringLiteral = 0;
|
|
|
|
|
CallAST *qlatin1Call = 0;
|
|
|
|
|
const QList<AST *> &path = state.path();
|
|
|
|
|
|
|
|
|
|
if (path.isEmpty())
|
|
|
|
|
return noResult(); // nothing to do
|
|
|
|
|
|
|
|
|
|
stringLiteral = path.last()->asStringLiteral();
|
|
|
|
|
|
|
|
|
|
if (! stringLiteral)
|
|
|
|
|
return noResult();
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
else if (file.charAt(file.startOf(stringLiteral)) == QLatin1Char('@'))
|
2010-07-26 13:06:33 +02:00
|
|
|
return noResult(); // it's already an objc string literal.
|
|
|
|
|
|
|
|
|
|
else if (path.size() > 1) {
|
|
|
|
|
if (CallAST *call = path.at(path.size() - 2)->asCall()) {
|
|
|
|
|
if (call->base_expression) {
|
2010-08-02 12:04:59 +02:00
|
|
|
if (IdExpressionAST *idExpr = call->base_expression->asIdExpression()) {
|
|
|
|
|
if (SimpleNameAST *functionName = idExpr->name->asSimpleName()) {
|
2010-08-13 12:49:11 +02:00
|
|
|
const QByteArray id(state.currentFile().tokenAt(functionName->identifier_token).identifier->chars());
|
2010-07-26 13:06:33 +02:00
|
|
|
|
2010-08-02 12:04:59 +02:00
|
|
|
if (id == "QLatin1String" || id == "QLatin1Literal")
|
|
|
|
|
qlatin1Call = call;
|
|
|
|
|
}
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return singleResult(new Operation(state, path.size() - 1, stringLiteral, qlatin1Call));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state, int priority, StringLiteralAST *stringLiteral, CallAST *qlatin1Call)
|
|
|
|
|
: CppQuickFixOperation(state, priority)
|
|
|
|
|
, stringLiteral(stringLiteral)
|
|
|
|
|
, qlatin1Call(qlatin1Call)
|
|
|
|
|
{
|
|
|
|
|
setDescription(QApplication::translate("CppTools::QuickFix",
|
|
|
|
|
"Convert to Objective-C String Literal"));
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
|
|
|
|
|
|
|
|
|
if (qlatin1Call) {
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.replace(currentFile->startOf(qlatin1Call), currentFile->startOf(stringLiteral), QLatin1String("@"));
|
|
|
|
|
changes.remove(currentFile->endOf(stringLiteral), currentFile->endOf(qlatin1Call));
|
2010-07-26 13:06:33 +02:00
|
|
|
} else {
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.insert(currentFile->startOf(stringLiteral), "@");
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
StringLiteralAST *stringLiteral;
|
|
|
|
|
CallAST *qlatin1Call;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
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
|
|
|
|
|
*/
|
|
|
|
|
class ConvertNumericLiteral: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<QuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
QList<QuickFixOperation::Ptr> result;
|
|
|
|
|
|
|
|
|
|
const QList<AST *> &path = state.path();
|
2010-08-13 12:49:11 +02:00
|
|
|
const CppRefactoringFile &file = state.currentFile();
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
if (path.isEmpty())
|
|
|
|
|
return result; // nothing to do
|
|
|
|
|
|
|
|
|
|
NumericLiteralAST *literal = path.last()->asNumericLiteral();
|
|
|
|
|
|
|
|
|
|
if (! literal)
|
|
|
|
|
return result;
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
Token token = file.tokenAt(literal->asNumericLiteral()->literal_token);
|
2010-07-26 13:06:33 +02:00
|
|
|
if (!token.is(T_NUMERIC_LITERAL))
|
|
|
|
|
return result;
|
|
|
|
|
const NumericLiteral *numeric = token.number;
|
|
|
|
|
if (numeric->isDouble() || numeric->isFloat())
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
// remove trailing L or U and stuff
|
|
|
|
|
const char * const spell = numeric->chars();
|
|
|
|
|
int numberLength = numeric->size();
|
|
|
|
|
while (numberLength > 0 && (spell[numberLength-1] < '0' || spell[numberLength-1] > 'F'))
|
|
|
|
|
--numberLength;
|
|
|
|
|
if (numberLength < 1)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
// convert to number
|
|
|
|
|
bool valid;
|
|
|
|
|
ulong value = QString::fromUtf8(spell).left(numberLength).toULong(&valid, 0);
|
|
|
|
|
if (!valid) // e.g. octal with digit > 7
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
const int priority = path.size() - 1; // very high priority
|
2010-08-13 12:49:11 +02:00
|
|
|
const int start = file.startOf(literal);
|
2010-07-26 13:06:33 +02:00
|
|
|
const char * const str = numeric->chars();
|
|
|
|
|
|
|
|
|
|
if (!numeric->isHex()) {
|
|
|
|
|
/*
|
|
|
|
|
Convert integer literal to hex representation.
|
|
|
|
|
Replace
|
|
|
|
|
32
|
|
|
|
|
040
|
|
|
|
|
With
|
|
|
|
|
0x20
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
QString replacement;
|
|
|
|
|
replacement.sprintf("0x%lX", value);
|
|
|
|
|
QuickFixOperation::Ptr op(new ConvertNumeric(state, start, start + numberLength, replacement));
|
|
|
|
|
op->setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Hexadecimal"));
|
|
|
|
|
op->setPriority(priority);
|
|
|
|
|
result.append(op);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value != 0) {
|
|
|
|
|
if (!(numberLength > 1 && str[0] == '0' && str[1] != 'x' && str[1] != 'X')) {
|
|
|
|
|
/*
|
|
|
|
|
Convert integer literal to octal representation.
|
|
|
|
|
Replace
|
|
|
|
|
32
|
|
|
|
|
0x20
|
|
|
|
|
With
|
|
|
|
|
040
|
|
|
|
|
*/
|
|
|
|
|
QString replacement;
|
|
|
|
|
replacement.sprintf("0%lo", value);
|
|
|
|
|
QuickFixOperation::Ptr op(new ConvertNumeric(state, start, start + numberLength, replacement));
|
|
|
|
|
op->setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Octal"));
|
|
|
|
|
op->setPriority(priority);
|
|
|
|
|
result.append(op);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value != 0 || numeric->isHex()) {
|
|
|
|
|
if (!(numberLength > 1 && str[0] != '0')) {
|
|
|
|
|
/*
|
|
|
|
|
Convert integer literal to decimal representation.
|
|
|
|
|
Replace
|
|
|
|
|
0x20
|
|
|
|
|
040
|
|
|
|
|
With
|
|
|
|
|
32
|
|
|
|
|
*/
|
|
|
|
|
QString replacement;
|
|
|
|
|
replacement.sprintf("%lu", value);
|
|
|
|
|
QuickFixOperation::Ptr op(new ConvertNumeric(state, start, start + numberLength, replacement));
|
|
|
|
|
op->setDescription(QApplication::translate("CppTools::QuickFix", "Convert to Decimal"));
|
|
|
|
|
op->setPriority(priority);
|
|
|
|
|
result.append(op);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class ConvertNumeric: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
ConvertNumeric(const CppQuickFixState &state, int start, int end, const QString &replacement)
|
|
|
|
|
: CppQuickFixOperation(state)
|
|
|
|
|
, start(start)
|
|
|
|
|
, end(end)
|
|
|
|
|
, replacement(replacement)
|
|
|
|
|
{}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
|
|
|
|
changes.replace(start, end, replacement);
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
int start, end;
|
|
|
|
|
QString replacement;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Adds missing case statements for "switch (enumVariable)"
|
|
|
|
|
*/
|
|
|
|
|
class CompleteSwitchCaseStatement: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
const QList<AST *> &path = state.path();
|
|
|
|
|
|
|
|
|
|
if (path.isEmpty())
|
|
|
|
|
return noResult(); // nothing to do
|
|
|
|
|
|
|
|
|
|
// look for switch statement
|
|
|
|
|
for (int depth = path.size() - 1; depth >= 0; --depth) {
|
|
|
|
|
AST *ast = path.at(depth);
|
|
|
|
|
SwitchStatementAST *switchStatement = ast->asSwitchStatement();
|
|
|
|
|
if (switchStatement) {
|
|
|
|
|
if (!state.isCursorOn(switchStatement->switch_token) || !switchStatement->statement)
|
|
|
|
|
return noResult();
|
|
|
|
|
CompoundStatementAST *compoundStatement = switchStatement->statement->asCompoundStatement();
|
|
|
|
|
if (!compoundStatement) // we ignore pathologic case "switch (t) case A: ;"
|
|
|
|
|
return noResult();
|
|
|
|
|
// look if the condition's type is an enum
|
|
|
|
|
if (Enum *e = conditionEnum(state, switchStatement)) {
|
|
|
|
|
// check the possible enum values
|
|
|
|
|
QStringList values;
|
|
|
|
|
Overview prettyPrint;
|
|
|
|
|
for (unsigned i = 0; i < e->memberCount(); ++i) {
|
|
|
|
|
if (Declaration *decl = e->memberAt(i)->asDeclaration()) {
|
|
|
|
|
values << prettyPrint(LookupContext::fullyQualifiedName(decl));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Get the used values
|
|
|
|
|
Block *block = switchStatement->symbol;
|
|
|
|
|
CaseStatementCollector caseValues(state.document(), state.snapshot(),
|
|
|
|
|
state.document()->scopeAt(block->line(), block->column()));
|
|
|
|
|
QStringList usedValues = caseValues(switchStatement);
|
|
|
|
|
// save the values that would be added
|
|
|
|
|
foreach (const QString &usedValue, usedValues)
|
|
|
|
|
values.removeAll(usedValue);
|
|
|
|
|
if (values.isEmpty())
|
|
|
|
|
return noResult();
|
|
|
|
|
return singleResult(new Operation(state, depth, compoundStatement, values));
|
|
|
|
|
}
|
|
|
|
|
return noResult();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return noResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
Enum *conditionEnum(const CppQuickFixState &state, SwitchStatementAST *statement)
|
|
|
|
|
{
|
|
|
|
|
Block *block = statement->symbol;
|
|
|
|
|
Scope *scope = state.document()->scopeAt(block->line(), block->column());
|
|
|
|
|
TypeOfExpression typeOfExpression;
|
|
|
|
|
typeOfExpression.init(state.document(), state.snapshot());
|
|
|
|
|
const QList<LookupItem> results = typeOfExpression(statement->condition,
|
|
|
|
|
state.document(),
|
|
|
|
|
scope);
|
2010-09-27 17:59:12 +02:00
|
|
|
|
|
|
|
|
///
|
|
|
|
|
/// \note FIXME: the lookup has at least two problems: the result.declaration()
|
|
|
|
|
/// will often be null, (i.e. when the condition is a function call)
|
|
|
|
|
/// and the lookups will not look through typedefs.
|
|
|
|
|
///
|
|
|
|
|
|
2010-07-26 13:06:33 +02:00
|
|
|
foreach (LookupItem result, results) {
|
|
|
|
|
FullySpecifiedType fst = result.type();
|
2010-09-03 16:44:18 +02:00
|
|
|
if (! result.declaration())
|
|
|
|
|
continue;
|
2010-07-26 13:06:33 +02:00
|
|
|
if (Enum *e = result.declaration()->type()->asEnumType())
|
|
|
|
|
return e;
|
|
|
|
|
if (NamedType *namedType = fst->asNamedType()) {
|
|
|
|
|
QList<LookupItem> candidates =
|
|
|
|
|
typeOfExpression.context().lookup(namedType->name(), scope);
|
|
|
|
|
foreach (const LookupItem &r, candidates) {
|
2010-09-03 16:44:18 +02:00
|
|
|
if (Symbol *candidate = r.declaration()) {
|
|
|
|
|
if (Enum *e = candidate->asEnum()) {
|
|
|
|
|
return e;
|
|
|
|
|
}
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class CaseStatementCollector : public ASTVisitor
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
CaseStatementCollector(Document::Ptr document, const Snapshot &snapshot,
|
|
|
|
|
Scope *scope)
|
|
|
|
|
: ASTVisitor(document->translationUnit()),
|
|
|
|
|
document(document),
|
|
|
|
|
scope(scope)
|
|
|
|
|
{
|
|
|
|
|
typeOfExpression.init(document, snapshot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList operator ()(AST *ast)
|
|
|
|
|
{
|
|
|
|
|
values.clear();
|
|
|
|
|
foundCaseStatementLevel = false;
|
|
|
|
|
accept(ast);
|
|
|
|
|
return values;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool preVisit(AST *ast) {
|
|
|
|
|
if (CaseStatementAST *cs = ast->asCaseStatement()) {
|
|
|
|
|
foundCaseStatementLevel = true;
|
2010-08-02 12:04:59 +02:00
|
|
|
if (ExpressionAST *expression = cs->expression->asIdExpression()) {
|
|
|
|
|
QList<LookupItem> candidates = typeOfExpression(expression,
|
|
|
|
|
document,
|
|
|
|
|
scope);
|
|
|
|
|
if (!candidates .isEmpty() && candidates.first().declaration()) {
|
|
|
|
|
Symbol *decl = candidates.first().declaration();
|
|
|
|
|
values << prettyPrint(LookupContext::fullyQualifiedName(decl));
|
|
|
|
|
}
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
} else if (foundCaseStatementLevel) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Overview prettyPrint;
|
|
|
|
|
bool foundCaseStatementLevel;
|
|
|
|
|
QStringList values;
|
|
|
|
|
TypeOfExpression typeOfExpression;
|
|
|
|
|
Document::Ptr document;
|
|
|
|
|
Scope *scope;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state, int priority, CompoundStatementAST *compoundStatement, const QStringList &values)
|
|
|
|
|
: CppQuickFixOperation(state, priority)
|
|
|
|
|
, compoundStatement(compoundStatement)
|
|
|
|
|
, values(values)
|
|
|
|
|
{
|
|
|
|
|
setDescription(QApplication::translate("CppTools::QuickFix",
|
|
|
|
|
"Complete Switch Statement"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
ChangeSet changes;
|
2010-08-13 12:49:11 +02:00
|
|
|
int start = currentFile->endOf(compoundStatement->lbrace_token);
|
2010-07-26 13:06:33 +02:00
|
|
|
changes.insert(start, QLatin1String("\ncase ")
|
|
|
|
|
+ values.join(QLatin1String(":\nbreak;\ncase "))
|
|
|
|
|
+ QLatin1String(":\nbreak;"));
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-08-13 12:49:11 +02:00
|
|
|
currentFile->indent(currentFile->range(compoundStatement));
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CompoundStatementAST *compoundStatement;
|
|
|
|
|
QStringList values;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class FixForwardDeclarationOp: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
const QList<AST *> &path = state.path();
|
|
|
|
|
|
|
|
|
|
for (int index = path.size() - 1; index != -1; --index) {
|
|
|
|
|
AST *ast = path.at(index);
|
|
|
|
|
if (NamedTypeSpecifierAST *namedTy = ast->asNamedTypeSpecifier()) {
|
|
|
|
|
if (Symbol *fwdClass = checkName(state, namedTy->name))
|
|
|
|
|
return singleResult(new Operation(state, index, fwdClass));
|
|
|
|
|
} else if (ElaboratedTypeSpecifierAST *eTy = ast->asElaboratedTypeSpecifier()) {
|
|
|
|
|
if (Symbol *fwdClass = checkName(state, eTy->name))
|
|
|
|
|
return singleResult(new Operation(state, index, fwdClass));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return noResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
static Symbol *checkName(const CppQuickFixState &state, NameAST *ast)
|
|
|
|
|
{
|
|
|
|
|
if (ast && state.isCursorOn(ast)) {
|
|
|
|
|
if (const Name *name = ast->name) {
|
|
|
|
|
unsigned line, column;
|
|
|
|
|
state.document()->translationUnit()->getTokenStartPosition(ast->firstToken(), &line, &column);
|
|
|
|
|
|
|
|
|
|
Symbol *fwdClass = 0;
|
|
|
|
|
|
|
|
|
|
foreach (const LookupItem &r, state.context().lookup(name, state.document()->scopeAt(line, column))) {
|
|
|
|
|
if (! r.declaration())
|
|
|
|
|
continue;
|
|
|
|
|
else if (ForwardClassDeclaration *fwd = r.declaration()->asForwardClassDeclaration())
|
|
|
|
|
fwdClass = fwd;
|
|
|
|
|
else if (r.declaration()->isClass())
|
|
|
|
|
return 0; // nothing to do.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fwdClass;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state, int priority, Symbol *fwdClass)
|
|
|
|
|
: CppQuickFixOperation(state, priority)
|
|
|
|
|
, fwdClass(fwdClass)
|
|
|
|
|
{
|
|
|
|
|
setDescription(QApplication::translate("CppTools::QuickFix",
|
2010-10-06 16:33:49 +02:00
|
|
|
"#include Header File"));
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(fwdClass != 0);
|
|
|
|
|
|
|
|
|
|
if (Class *k = state().snapshot().findMatchingClassDeclaration(fwdClass)) {
|
|
|
|
|
const QString headerFile = QString::fromUtf8(k->fileName(), k->fileNameLength());
|
|
|
|
|
|
|
|
|
|
// collect the fwd headers
|
|
|
|
|
Snapshot fwdHeaders;
|
|
|
|
|
fwdHeaders.insert(state().snapshot().document(headerFile));
|
|
|
|
|
foreach (Document::Ptr doc, state().snapshot()) {
|
|
|
|
|
QFileInfo headerFileInfo(doc->fileName());
|
|
|
|
|
if (doc->globalSymbolCount() == 0 && doc->includes().size() == 1)
|
|
|
|
|
fwdHeaders.insert(doc);
|
|
|
|
|
else if (headerFileInfo.suffix().isEmpty())
|
|
|
|
|
fwdHeaders.insert(doc);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DependencyTable dep;
|
|
|
|
|
dep.build(fwdHeaders);
|
|
|
|
|
QStringList candidates = dep.dependencyTable().value(headerFile);
|
|
|
|
|
|
|
|
|
|
const QString className = QString::fromUtf8(k->identifier()->chars());
|
|
|
|
|
|
|
|
|
|
QString best;
|
|
|
|
|
foreach (const QString &c, candidates) {
|
|
|
|
|
QFileInfo headerFileInfo(c);
|
|
|
|
|
if (headerFileInfo.fileName() == className) {
|
|
|
|
|
best = c;
|
|
|
|
|
break;
|
|
|
|
|
} else if (headerFileInfo.fileName().at(0).isUpper()) {
|
|
|
|
|
best = c;
|
|
|
|
|
// and continue
|
|
|
|
|
} else if (! best.isEmpty()) {
|
|
|
|
|
if (c.count(QLatin1Char('/')) < best.count(QLatin1Char('/')))
|
|
|
|
|
best = c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (best.isEmpty())
|
|
|
|
|
best = headerFile;
|
|
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
int pos = currentFile->startOf(1);
|
2010-07-26 13:06:33 +02:00
|
|
|
|
2010-08-13 12:49:11 +02:00
|
|
|
unsigned currentLine = currentFile->cursor().blockNumber() + 1;
|
2010-07-26 13:06:33 +02:00
|
|
|
unsigned bestLine = 0;
|
|
|
|
|
foreach (const Document::Include &incl, state().document()->includes()) {
|
|
|
|
|
if (incl.line() < currentLine)
|
|
|
|
|
bestLine = incl.line();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bestLine)
|
2010-08-13 12:49:11 +02:00
|
|
|
pos = currentFile->document()->findBlockByNumber(bestLine).position();
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
Utils::ChangeSet changes;
|
|
|
|
|
changes.insert(pos, QString("#include <%1>\n").arg(QFileInfo(best).fileName()));
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
Symbol *fwdClass;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class AddLocalDeclarationOp: public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
const QList<AST *> &path = state.path();
|
2010-08-13 12:49:11 +02:00
|
|
|
const CppRefactoringFile &file = state.currentFile();
|
2010-07-26 13:06:33 +02:00
|
|
|
|
|
|
|
|
for (int index = path.size() - 1; index != -1; --index) {
|
|
|
|
|
if (BinaryExpressionAST *binary = path.at(index)->asBinaryExpression()) {
|
2010-08-13 12:49:11 +02:00
|
|
|
if (binary->left_expression && binary->right_expression && file.tokenAt(binary->binary_op_token).is(T_EQUAL)) {
|
2010-08-02 12:04:59 +02:00
|
|
|
IdExpressionAST *idExpr = binary->left_expression->asIdExpression();
|
|
|
|
|
if (state.isCursorOn(binary->left_expression) && idExpr && idExpr->name->asSimpleName() != 0) {
|
|
|
|
|
SimpleNameAST *nameAST = idExpr->name->asSimpleName();
|
2010-08-13 12:49:11 +02:00
|
|
|
const QList<LookupItem> results = state.context().lookup(nameAST->name, file.scopeAt(nameAST->firstToken()));
|
2010-07-26 13:06:33 +02:00
|
|
|
Declaration *decl = 0;
|
|
|
|
|
foreach (const LookupItem &r, results) {
|
|
|
|
|
if (! r.declaration())
|
|
|
|
|
continue;
|
|
|
|
|
else if (Declaration *d = r.declaration()->asDeclaration()) {
|
|
|
|
|
if (! d->type()->isFunctionType()) {
|
|
|
|
|
decl = d;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (! decl) {
|
|
|
|
|
return singleResult(new Operation(state, index, binary));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return noResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state, int priority, BinaryExpressionAST *binaryAST)
|
|
|
|
|
: CppQuickFixOperation(state, priority)
|
|
|
|
|
, binaryAST(binaryAST)
|
|
|
|
|
{
|
2010-10-06 16:33:49 +02:00
|
|
|
setDescription(QApplication::translate("CppTools::QuickFix", "Add local Declaration"));
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *currentFile, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
TypeOfExpression typeOfExpression;
|
|
|
|
|
typeOfExpression.init(state().document(), state().snapshot(), state().context().bindings());
|
2010-08-13 12:49:11 +02:00
|
|
|
const QList<LookupItem> result = typeOfExpression(currentFile->textOf(binaryAST->right_expression),
|
|
|
|
|
currentFile->scopeAt(binaryAST->firstToken()),
|
2010-07-26 13:06:33 +02:00
|
|
|
TypeOfExpression::Preprocess);
|
|
|
|
|
|
|
|
|
|
if (! result.isEmpty()) {
|
|
|
|
|
|
|
|
|
|
SubstitutionEnvironment env;
|
|
|
|
|
env.setContext(state().context());
|
|
|
|
|
env.switchScope(result.first().scope());
|
|
|
|
|
UseQualifiedNames q;
|
|
|
|
|
env.enter(&q);
|
|
|
|
|
|
|
|
|
|
Control *control = state().context().control().data();
|
|
|
|
|
FullySpecifiedType tn = rewriteType(result.first().type(), &env, control);
|
|
|
|
|
|
|
|
|
|
Overview oo;
|
|
|
|
|
QString ty = oo(tn);
|
|
|
|
|
if (! ty.isEmpty()) {
|
|
|
|
|
const QChar ch = ty.at(ty.size() - 1);
|
|
|
|
|
|
|
|
|
|
if (ch.isLetterOrNumber() || ch == QLatin1Char(' ') || ch == QLatin1Char('>'))
|
|
|
|
|
ty += QLatin1Char(' ');
|
|
|
|
|
|
|
|
|
|
Utils::ChangeSet changes;
|
2010-08-13 12:49:11 +02:00
|
|
|
changes.insert(currentFile->startOf(binaryAST), ty);
|
2010-08-12 13:46:18 +02:00
|
|
|
currentFile->change(changes);
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
BinaryExpressionAST *binaryAST;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Turns "an_example_symbol" into "anExampleSymbol" and
|
|
|
|
|
* "AN_EXAMPLE_SYMBOL" into "AnExampleSymbol".
|
|
|
|
|
*/
|
|
|
|
|
class ToCamelCaseConverter : public CppQuickFixFactory
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
virtual QList<CppQuickFixOperation::Ptr> match(const CppQuickFixState &state)
|
|
|
|
|
{
|
|
|
|
|
const QList<AST *> &path = state.path();
|
|
|
|
|
|
|
|
|
|
if (path.isEmpty())
|
|
|
|
|
return noResult();
|
|
|
|
|
|
|
|
|
|
AST * const ast = path.last();
|
|
|
|
|
const Name *name = 0;
|
|
|
|
|
if (const NameAST * const nameAst = ast->asName()) {
|
|
|
|
|
if (nameAst->name && nameAst->name->asNameId())
|
|
|
|
|
name = nameAst->name;
|
|
|
|
|
} else if (const NamespaceAST * const namespaceAst = ast->asNamespace()) {
|
|
|
|
|
name = namespaceAst->symbol->name();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
|
return noResult();
|
|
|
|
|
|
|
|
|
|
QString newName = QString::fromUtf8(name->identifier()->chars());
|
|
|
|
|
if (newName.length() < 3)
|
|
|
|
|
return noResult();
|
|
|
|
|
for (int i = 1; i < newName.length() - 1; ++i) {
|
|
|
|
|
if (Operation::isConvertibleUnderscore(newName, i))
|
|
|
|
|
return singleResult(new Operation(state, path.size() - 1, newName));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return noResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
class Operation: public CppQuickFixOperation
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
Operation(const CppQuickFixState &state, int priority, const QString &newName)
|
|
|
|
|
: CppQuickFixOperation(state, priority)
|
|
|
|
|
, m_name(newName)
|
|
|
|
|
{
|
|
|
|
|
setDescription(QApplication::translate("CppTools::QuickFix",
|
|
|
|
|
"Convert to Camel Case ..."));
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-13 11:48:29 +02:00
|
|
|
virtual void performChanges(CppRefactoringFile *, CppRefactoringChanges *)
|
2010-07-26 13:06:33 +02:00
|
|
|
{
|
|
|
|
|
for (int i = 1; i < m_name.length(); ++i) {
|
|
|
|
|
QCharRef c = m_name[i];
|
|
|
|
|
if (c.isUpper()) {
|
|
|
|
|
c = c.toLower();
|
|
|
|
|
} else if (i < m_name.length() - 1
|
|
|
|
|
&& isConvertibleUnderscore(m_name, i)) {
|
|
|
|
|
m_name.remove(i, 1);
|
|
|
|
|
m_name[i] = m_name.at(i).toUpper();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
static_cast<CppEditor::Internal::CPPEditor*>(state().editor())->renameUsagesNow(m_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool isConvertibleUnderscore(const QString &name, int pos)
|
|
|
|
|
{
|
|
|
|
|
return name.at(pos) == QLatin1Char('_') && name.at(pos+1).isLetter()
|
|
|
|
|
&& !(pos == 1 && name.at(0) == QLatin1Char('m'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
QString m_name;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // end of anonymous namespace
|
|
|
|
|
|
|
|
|
|
void CppQuickFixCollector::registerQuickFixes(ExtensionSystem::IPlugin *plugIn)
|
|
|
|
|
{
|
|
|
|
|
plugIn->addAutoReleasedObject(new UseInverseOp);
|
|
|
|
|
plugIn->addAutoReleasedObject(new FlipBinaryOp);
|
|
|
|
|
plugIn->addAutoReleasedObject(new RewriteLogicalAndOp);
|
|
|
|
|
plugIn->addAutoReleasedObject(new SplitSimpleDeclarationOp);
|
|
|
|
|
plugIn->addAutoReleasedObject(new AddBracesToIfOp);
|
|
|
|
|
plugIn->addAutoReleasedObject(new MoveDeclarationOutOfIfOp);
|
|
|
|
|
plugIn->addAutoReleasedObject(new MoveDeclarationOutOfWhileOp);
|
|
|
|
|
plugIn->addAutoReleasedObject(new SplitIfStatementOp);
|
|
|
|
|
plugIn->addAutoReleasedObject(new WrapStringLiteral);
|
|
|
|
|
plugIn->addAutoReleasedObject(new TranslateStringLiteral);
|
|
|
|
|
plugIn->addAutoReleasedObject(new CStringToNSString);
|
|
|
|
|
plugIn->addAutoReleasedObject(new ConvertNumericLiteral);
|
2010-09-27 17:59:12 +02:00
|
|
|
// Disabled for now: see the CompleteSwitchCaseStatement class for the reason.
|
|
|
|
|
// plugIn->addAutoReleasedObject(new CompleteSwitchCaseStatement);
|
2010-07-26 13:06:33 +02:00
|
|
|
plugIn->addAutoReleasedObject(new FixForwardDeclarationOp);
|
|
|
|
|
plugIn->addAutoReleasedObject(new AddLocalDeclarationOp);
|
|
|
|
|
plugIn->addAutoReleasedObject(new ToCamelCaseConverter);
|
|
|
|
|
plugIn->addAutoReleasedObject(new Internal::DeclFromDef);
|
2010-09-27 17:59:12 +02:00
|
|
|
plugIn->addAutoReleasedObject(new Internal::DefFromDecl);
|
2010-07-26 13:06:33 +02:00
|
|
|
}
|