forked from qt-creator/qt-creator
Move quickfixes for logical operations into dedicated files
Change-Id: Ie0009820b7320ed71331e1611d6cf9701c54c089 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -111,6 +111,7 @@ add_qtc_plugin(CppEditor
|
|||||||
quickfixes/cppquickfixsettingswidget.cpp quickfixes/cppquickfixsettingswidget.h
|
quickfixes/cppquickfixsettingswidget.cpp quickfixes/cppquickfixsettingswidget.h
|
||||||
quickfixes/createdeclarationfromuse.cpp quickfixes/createdeclarationfromuse.h
|
quickfixes/createdeclarationfromuse.cpp quickfixes/createdeclarationfromuse.h
|
||||||
quickfixes/insertfunctiondefinition.cpp quickfixes/insertfunctiondefinition.h
|
quickfixes/insertfunctiondefinition.cpp quickfixes/insertfunctiondefinition.h
|
||||||
|
quickfixes/logicaloperationquickfixes.cpp quickfixes/logicaloperationquickfixes.h
|
||||||
quickfixes/moveclasstoownfile.cpp quickfixes/moveclasstoownfile.h
|
quickfixes/moveclasstoownfile.cpp quickfixes/moveclasstoownfile.h
|
||||||
quickfixes/movefunctiondefinition.cpp quickfixes/movefunctiondefinition.h
|
quickfixes/movefunctiondefinition.cpp quickfixes/movefunctiondefinition.h
|
||||||
quickfixes/removeusingnamespace.cpp quickfixes/removeusingnamespace.h
|
quickfixes/removeusingnamespace.cpp quickfixes/removeusingnamespace.h
|
||||||
|
@@ -251,6 +251,8 @@ QtcPlugin {
|
|||||||
"createdeclarationfromuse.h",
|
"createdeclarationfromuse.h",
|
||||||
"insertfunctiondefinition.cpp",
|
"insertfunctiondefinition.cpp",
|
||||||
"insertfunctiondefinition.h",
|
"insertfunctiondefinition.h",
|
||||||
|
"logicaloperationquickfixes.cpp",
|
||||||
|
"logicaloperationquickfixes.h",
|
||||||
"moveclasstoownfile.cpp",
|
"moveclasstoownfile.cpp",
|
||||||
"moveclasstoownfile.h",
|
"moveclasstoownfile.h",
|
||||||
"movefunctiondefinition.cpp",
|
"movefunctiondefinition.cpp",
|
||||||
|
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include "../baseeditordocumentprocessor.h"
|
#include "../baseeditordocumentprocessor.h"
|
||||||
#include "../cppcodestylesettings.h"
|
#include "../cppcodestylesettings.h"
|
||||||
#include "../cppeditordocument.h"
|
|
||||||
#include "../cppeditortr.h"
|
#include "../cppeditortr.h"
|
||||||
#include "../cppeditorwidget.h"
|
#include "../cppeditorwidget.h"
|
||||||
#include "../cppfunctiondecldeflink.h"
|
#include "../cppfunctiondecldeflink.h"
|
||||||
@@ -25,6 +24,7 @@
|
|||||||
#include "convertstringliteral.h"
|
#include "convertstringliteral.h"
|
||||||
#include "createdeclarationfromuse.h"
|
#include "createdeclarationfromuse.h"
|
||||||
#include "insertfunctiondefinition.h"
|
#include "insertfunctiondefinition.h"
|
||||||
|
#include "logicaloperationquickfixes.h"
|
||||||
#include "moveclasstoownfile.h"
|
#include "moveclasstoownfile.h"
|
||||||
#include "movefunctiondefinition.h"
|
#include "movefunctiondefinition.h"
|
||||||
#include "removeusingnamespace.h"
|
#include "removeusingnamespace.h"
|
||||||
@@ -37,6 +37,7 @@
|
|||||||
#include <cplusplus/CppRewriter.h>
|
#include <cplusplus/CppRewriter.h>
|
||||||
#include <cplusplus/declarationcomments.h>
|
#include <cplusplus/declarationcomments.h>
|
||||||
#include <cplusplus/NamePrettyPrinter.h>
|
#include <cplusplus/NamePrettyPrinter.h>
|
||||||
|
#include <cplusplus/Overview.h>
|
||||||
#include <cplusplus/TypeOfExpression.h>
|
#include <cplusplus/TypeOfExpression.h>
|
||||||
#include <cplusplus/TypePrettyPrinter.h>
|
#include <cplusplus/TypePrettyPrinter.h>
|
||||||
|
|
||||||
@@ -129,276 +130,6 @@ const QList<CppQuickFixFactory *> &CppQuickFixFactory::cppQuickFixFactories()
|
|||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class InverseLogicalComparisonOp: public CppQuickFixOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
InverseLogicalComparisonOp(const CppQuickFixInterface &interface,
|
|
||||||
int priority,
|
|
||||||
BinaryExpressionAST *binary,
|
|
||||||
Kind invertToken)
|
|
||||||
: CppQuickFixOperation(interface, priority)
|
|
||||||
, binary(binary)
|
|
||||||
{
|
|
||||||
Token tok;
|
|
||||||
tok.f.kind = invertToken;
|
|
||||||
replacement = QLatin1String(tok.spell());
|
|
||||||
|
|
||||||
// check for enclosing nested expression
|
|
||||||
if (priority - 1 >= 0)
|
|
||||||
nested = interface.path()[priority - 1]->asNestedExpression();
|
|
||||||
|
|
||||||
// check for ! before parentheses
|
|
||||||
if (nested && priority - 2 >= 0) {
|
|
||||||
negation = interface.path()[priority - 2]->asUnaryExpression();
|
|
||||||
if (negation && !interface.currentFile()->tokenAt(negation->unary_op_token).is(T_EXCLAIM))
|
|
||||||
negation = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString description() const override
|
|
||||||
{
|
|
||||||
return Tr::tr("Rewrite Using %1").arg(replacement);
|
|
||||||
}
|
|
||||||
|
|
||||||
void perform() override
|
|
||||||
{
|
|
||||||
CppRefactoringChanges refactoring(snapshot());
|
|
||||||
CppRefactoringFilePtr currentFile = refactoring.cppFile(filePath());
|
|
||||||
|
|
||||||
ChangeSet changes;
|
|
||||||
if (negation) {
|
|
||||||
// can't remove parentheses since that might break precedence
|
|
||||||
changes.remove(currentFile->range(negation->unary_op_token));
|
|
||||||
} else if (nested) {
|
|
||||||
changes.insert(currentFile->startOf(nested), QLatin1String("!"));
|
|
||||||
} else {
|
|
||||||
changes.insert(currentFile->startOf(binary), QLatin1String("!("));
|
|
||||||
changes.insert(currentFile->endOf(binary), QLatin1String(")"));
|
|
||||||
}
|
|
||||||
changes.replace(currentFile->range(binary->binary_op_token), replacement);
|
|
||||||
currentFile->setChangeSet(changes);
|
|
||||||
currentFile->apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BinaryExpressionAST *binary = nullptr;
|
|
||||||
NestedExpressionAST *nested = nullptr;
|
|
||||||
UnaryExpressionAST *negation = nullptr;
|
|
||||||
|
|
||||||
QString replacement;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void InverseLogicalComparison::doMatch(const CppQuickFixInterface &interface,
|
|
||||||
QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
CppRefactoringFilePtr file = interface.currentFile();
|
|
||||||
|
|
||||||
const QList<AST *> &path = interface.path();
|
|
||||||
if (path.isEmpty())
|
|
||||||
return;
|
|
||||||
int index = path.size() - 1;
|
|
||||||
BinaryExpressionAST *binary = path.at(index)->asBinaryExpression();
|
|
||||||
if (!binary)
|
|
||||||
return;
|
|
||||||
if (!interface.isCursorOn(binary->binary_op_token))
|
|
||||||
return;
|
|
||||||
|
|
||||||
Kind invertToken;
|
|
||||||
switch (file->tokenAt(binary->binary_op_token).kind()) {
|
|
||||||
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 << new InverseLogicalComparisonOp(interface, index, binary, invertToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class FlipLogicalOperandsOp: public CppQuickFixOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FlipLogicalOperandsOp(const CppQuickFixInterface &interface, int priority,
|
|
||||||
BinaryExpressionAST *binary, QString replacement)
|
|
||||||
: CppQuickFixOperation(interface)
|
|
||||||
, binary(binary)
|
|
||||||
, replacement(replacement)
|
|
||||||
{
|
|
||||||
setPriority(priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString description() const override
|
|
||||||
{
|
|
||||||
if (replacement.isEmpty())
|
|
||||||
return Tr::tr("Swap Operands");
|
|
||||||
else
|
|
||||||
return Tr::tr("Rewrite Using %1").arg(replacement);
|
|
||||||
}
|
|
||||||
|
|
||||||
void perform() override
|
|
||||||
{
|
|
||||||
CppRefactoringChanges refactoring(snapshot());
|
|
||||||
CppRefactoringFilePtr currentFile = refactoring.cppFile(filePath());
|
|
||||||
|
|
||||||
ChangeSet changes;
|
|
||||||
changes.flip(currentFile->range(binary->left_expression),
|
|
||||||
currentFile->range(binary->right_expression));
|
|
||||||
if (!replacement.isEmpty())
|
|
||||||
changes.replace(currentFile->range(binary->binary_op_token), replacement);
|
|
||||||
|
|
||||||
currentFile->setChangeSet(changes);
|
|
||||||
currentFile->apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BinaryExpressionAST *binary;
|
|
||||||
QString replacement;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void FlipLogicalOperands::doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
const QList<AST *> &path = interface.path();
|
|
||||||
if (path.isEmpty())
|
|
||||||
return;
|
|
||||||
CppRefactoringFilePtr file = interface.currentFile();
|
|
||||||
|
|
||||||
int index = path.size() - 1;
|
|
||||||
BinaryExpressionAST *binary = path.at(index)->asBinaryExpression();
|
|
||||||
if (!binary)
|
|
||||||
return;
|
|
||||||
if (!interface.isCursorOn(binary->binary_op_token))
|
|
||||||
return;
|
|
||||||
|
|
||||||
Kind flipToken;
|
|
||||||
switch (file->tokenAt(binary->binary_op_token).kind()) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString replacement;
|
|
||||||
if (flipToken != T_EOF_SYMBOL) {
|
|
||||||
Token tok;
|
|
||||||
tok.f.kind = flipToken;
|
|
||||||
replacement = QLatin1String(tok.spell());
|
|
||||||
}
|
|
||||||
|
|
||||||
result << new FlipLogicalOperandsOp(interface, index, binary, replacement);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class RewriteLogicalAndOp: public CppQuickFixOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
std::shared_ptr<ASTPatternBuilder> mk;
|
|
||||||
UnaryExpressionAST *left;
|
|
||||||
UnaryExpressionAST *right;
|
|
||||||
BinaryExpressionAST *pattern;
|
|
||||||
|
|
||||||
RewriteLogicalAndOp(const CppQuickFixInterface &interface)
|
|
||||||
: CppQuickFixOperation(interface)
|
|
||||||
, mk(new ASTPatternBuilder)
|
|
||||||
{
|
|
||||||
left = mk->UnaryExpression();
|
|
||||||
right = mk->UnaryExpression();
|
|
||||||
pattern = mk->BinaryExpression(left, right);
|
|
||||||
}
|
|
||||||
|
|
||||||
void perform() override
|
|
||||||
{
|
|
||||||
CppRefactoringChanges refactoring(snapshot());
|
|
||||||
CppRefactoringFilePtr currentFile = refactoring.cppFile(filePath());
|
|
||||||
|
|
||||||
ChangeSet changes;
|
|
||||||
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);
|
|
||||||
changes.insert(start, QLatin1String("!("));
|
|
||||||
changes.insert(end, QLatin1String(")"));
|
|
||||||
|
|
||||||
currentFile->setChangeSet(changes);
|
|
||||||
currentFile->apply();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void RewriteLogicalAnd::doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
BinaryExpressionAST *expression = nullptr;
|
|
||||||
const QList<AST *> &path = interface.path();
|
|
||||||
CppRefactoringFilePtr file = interface.currentFile();
|
|
||||||
|
|
||||||
int index = path.size() - 1;
|
|
||||||
for (; index != -1; --index) {
|
|
||||||
expression = path.at(index)->asBinaryExpression();
|
|
||||||
if (expression)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!expression)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!interface.isCursorOn(expression->binary_op_token))
|
|
||||||
return;
|
|
||||||
|
|
||||||
QSharedPointer<RewriteLogicalAndOp> op(new RewriteLogicalAndOp(interface));
|
|
||||||
|
|
||||||
ASTMatcher matcher;
|
|
||||||
|
|
||||||
if (expression->match(op->pattern, &matcher) &&
|
|
||||||
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)) {
|
|
||||||
op->setDescription(Tr::tr("Rewrite Condition Using ||"));
|
|
||||||
op->setPriority(index);
|
|
||||||
result.append(op);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool checkDeclarationForSplit(SimpleDeclarationAST *declaration)
|
static bool checkDeclarationForSplit(SimpleDeclarationAST *declaration)
|
||||||
{
|
{
|
||||||
if (!declaration->semicolon_token)
|
if (!declaration->semicolon_token)
|
||||||
@@ -3834,10 +3565,6 @@ void ConvertToMetaMethodCall::doMatch(const CppQuickFixInterface &interface,
|
|||||||
|
|
||||||
void createCppQuickFixes()
|
void createCppQuickFixes()
|
||||||
{
|
{
|
||||||
new FlipLogicalOperands;
|
|
||||||
new InverseLogicalComparison;
|
|
||||||
new RewriteLogicalAnd;
|
|
||||||
|
|
||||||
new ConvertToCamelCase;
|
new ConvertToCamelCase;
|
||||||
|
|
||||||
new ConvertNumericLiteral;
|
new ConvertNumericLiteral;
|
||||||
@@ -3871,6 +3598,7 @@ void createCppQuickFixes()
|
|||||||
registerBringIdentifierIntoScopeQuickfixes();
|
registerBringIdentifierIntoScopeQuickfixes();
|
||||||
registerConvertStringLiteralQuickfixes();
|
registerConvertStringLiteralQuickfixes();
|
||||||
registerCreateDeclarationFromUseQuickfixes();
|
registerCreateDeclarationFromUseQuickfixes();
|
||||||
|
registerLogicalOperationQuickfixes();
|
||||||
|
|
||||||
new OptimizeForLoop;
|
new OptimizeForLoop;
|
||||||
|
|
||||||
|
@@ -28,51 +28,6 @@ public:
|
|||||||
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override;
|
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
|
||||||
Rewrite
|
|
||||||
a op b
|
|
||||||
|
|
||||||
As
|
|
||||||
b flipop a
|
|
||||||
|
|
||||||
Activates on: <= < > >= == != && ||
|
|
||||||
*/
|
|
||||||
class FlipLogicalOperands: public CppQuickFixFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
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 doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Rewrite
|
|
||||||
!a && !b
|
|
||||||
|
|
||||||
As
|
|
||||||
!(a || b)
|
|
||||||
|
|
||||||
Activates on: &&
|
|
||||||
*/
|
|
||||||
class RewriteLogicalAnd: public CppQuickFixFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Base class for converting numeric literals between decimal, octal and hex.
|
Base class for converting numeric literals between decimal, octal and hex.
|
||||||
Does the base check for the specific ones and parses the number.
|
Does the base check for the specific ones and parses the number.
|
||||||
|
335
src/plugins/cppeditor/quickfixes/logicaloperationquickfixes.cpp
Normal file
335
src/plugins/cppeditor/quickfixes/logicaloperationquickfixes.cpp
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#include "logicaloperationquickfixes.h"
|
||||||
|
|
||||||
|
#include "../cppeditortr.h"
|
||||||
|
#include "../cpprefactoringchanges.h"
|
||||||
|
#include "cppquickfix.h"
|
||||||
|
|
||||||
|
using namespace CPlusPlus;
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
|
namespace CppEditor::Internal {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class FlipLogicalOperandsOp : public CppQuickFixOperation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FlipLogicalOperandsOp(const CppQuickFixInterface &interface, int priority,
|
||||||
|
BinaryExpressionAST *binary, QString replacement)
|
||||||
|
: CppQuickFixOperation(interface)
|
||||||
|
, binary(binary)
|
||||||
|
, replacement(replacement)
|
||||||
|
{
|
||||||
|
setPriority(priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString description() const override
|
||||||
|
{
|
||||||
|
if (replacement.isEmpty())
|
||||||
|
return Tr::tr("Swap Operands");
|
||||||
|
else
|
||||||
|
return Tr::tr("Rewrite Using %1").arg(replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void perform() override
|
||||||
|
{
|
||||||
|
CppRefactoringChanges refactoring(snapshot());
|
||||||
|
CppRefactoringFilePtr currentFile = refactoring.cppFile(filePath());
|
||||||
|
|
||||||
|
ChangeSet changes;
|
||||||
|
changes.flip(currentFile->range(binary->left_expression),
|
||||||
|
currentFile->range(binary->right_expression));
|
||||||
|
if (!replacement.isEmpty())
|
||||||
|
changes.replace(currentFile->range(binary->binary_op_token), replacement);
|
||||||
|
|
||||||
|
currentFile->setChangeSet(changes);
|
||||||
|
currentFile->apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BinaryExpressionAST *binary;
|
||||||
|
QString replacement;
|
||||||
|
};
|
||||||
|
|
||||||
|
class InverseLogicalComparisonOp : public CppQuickFixOperation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InverseLogicalComparisonOp(const CppQuickFixInterface &interface,
|
||||||
|
int priority,
|
||||||
|
BinaryExpressionAST *binary,
|
||||||
|
Kind invertToken)
|
||||||
|
: CppQuickFixOperation(interface, priority)
|
||||||
|
, binary(binary)
|
||||||
|
{
|
||||||
|
Token tok;
|
||||||
|
tok.f.kind = invertToken;
|
||||||
|
replacement = QLatin1String(tok.spell());
|
||||||
|
|
||||||
|
// check for enclosing nested expression
|
||||||
|
if (priority - 1 >= 0)
|
||||||
|
nested = interface.path()[priority - 1]->asNestedExpression();
|
||||||
|
|
||||||
|
// check for ! before parentheses
|
||||||
|
if (nested && priority - 2 >= 0) {
|
||||||
|
negation = interface.path()[priority - 2]->asUnaryExpression();
|
||||||
|
if (negation && !interface.currentFile()->tokenAt(negation->unary_op_token).is(T_EXCLAIM))
|
||||||
|
negation = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString description() const override
|
||||||
|
{
|
||||||
|
return Tr::tr("Rewrite Using %1").arg(replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
void perform() override
|
||||||
|
{
|
||||||
|
CppRefactoringChanges refactoring(snapshot());
|
||||||
|
CppRefactoringFilePtr currentFile = refactoring.cppFile(filePath());
|
||||||
|
|
||||||
|
ChangeSet changes;
|
||||||
|
if (negation) {
|
||||||
|
// can't remove parentheses since that might break precedence
|
||||||
|
changes.remove(currentFile->range(negation->unary_op_token));
|
||||||
|
} else if (nested) {
|
||||||
|
changes.insert(currentFile->startOf(nested), QLatin1String("!"));
|
||||||
|
} else {
|
||||||
|
changes.insert(currentFile->startOf(binary), QLatin1String("!("));
|
||||||
|
changes.insert(currentFile->endOf(binary), QLatin1String(")"));
|
||||||
|
}
|
||||||
|
changes.replace(currentFile->range(binary->binary_op_token), replacement);
|
||||||
|
currentFile->setChangeSet(changes);
|
||||||
|
currentFile->apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BinaryExpressionAST *binary = nullptr;
|
||||||
|
NestedExpressionAST *nested = nullptr;
|
||||||
|
UnaryExpressionAST *negation = nullptr;
|
||||||
|
|
||||||
|
QString replacement;
|
||||||
|
};
|
||||||
|
|
||||||
|
class RewriteLogicalAndOp : public CppQuickFixOperation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::shared_ptr<ASTPatternBuilder> mk;
|
||||||
|
UnaryExpressionAST *left;
|
||||||
|
UnaryExpressionAST *right;
|
||||||
|
BinaryExpressionAST *pattern;
|
||||||
|
|
||||||
|
RewriteLogicalAndOp(const CppQuickFixInterface &interface)
|
||||||
|
: CppQuickFixOperation(interface)
|
||||||
|
, mk(new ASTPatternBuilder)
|
||||||
|
{
|
||||||
|
left = mk->UnaryExpression();
|
||||||
|
right = mk->UnaryExpression();
|
||||||
|
pattern = mk->BinaryExpression(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
void perform() override
|
||||||
|
{
|
||||||
|
CppRefactoringChanges refactoring(snapshot());
|
||||||
|
CppRefactoringFilePtr currentFile = refactoring.cppFile(filePath());
|
||||||
|
|
||||||
|
ChangeSet changes;
|
||||||
|
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);
|
||||||
|
changes.insert(start, QLatin1String("!("));
|
||||||
|
changes.insert(end, QLatin1String(")"));
|
||||||
|
|
||||||
|
currentFile->setChangeSet(changes);
|
||||||
|
currentFile->apply();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Rewrite
|
||||||
|
a op b
|
||||||
|
|
||||||
|
As
|
||||||
|
b flipop a
|
||||||
|
|
||||||
|
Activates on: <= < > >= == != && ||
|
||||||
|
*/
|
||||||
|
class FlipLogicalOperands : public CppQuickFixFactory
|
||||||
|
{
|
||||||
|
#ifdef WITH_TESTS
|
||||||
|
public:
|
||||||
|
static QObject *createTest() { return new QObject; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override
|
||||||
|
{
|
||||||
|
const QList<AST *> &path = interface.path();
|
||||||
|
if (path.isEmpty())
|
||||||
|
return;
|
||||||
|
CppRefactoringFilePtr file = interface.currentFile();
|
||||||
|
|
||||||
|
int index = path.size() - 1;
|
||||||
|
BinaryExpressionAST *binary = path.at(index)->asBinaryExpression();
|
||||||
|
if (!binary)
|
||||||
|
return;
|
||||||
|
if (!interface.isCursorOn(binary->binary_op_token))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Kind flipToken;
|
||||||
|
switch (file->tokenAt(binary->binary_op_token).kind()) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString replacement;
|
||||||
|
if (flipToken != T_EOF_SYMBOL) {
|
||||||
|
Token tok;
|
||||||
|
tok.f.kind = flipToken;
|
||||||
|
replacement = QLatin1String(tok.spell());
|
||||||
|
}
|
||||||
|
|
||||||
|
result << new FlipLogicalOperandsOp(interface, index, binary, replacement);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
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
|
||||||
|
{
|
||||||
|
#ifdef WITH_TESTS
|
||||||
|
public:
|
||||||
|
static QObject *createTest() { return new QObject; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override
|
||||||
|
{
|
||||||
|
CppRefactoringFilePtr file = interface.currentFile();
|
||||||
|
|
||||||
|
const QList<AST *> &path = interface.path();
|
||||||
|
if (path.isEmpty())
|
||||||
|
return;
|
||||||
|
int index = path.size() - 1;
|
||||||
|
BinaryExpressionAST *binary = path.at(index)->asBinaryExpression();
|
||||||
|
if (!binary)
|
||||||
|
return;
|
||||||
|
if (!interface.isCursorOn(binary->binary_op_token))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Kind invertToken;
|
||||||
|
switch (file->tokenAt(binary->binary_op_token).kind()) {
|
||||||
|
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 << new InverseLogicalComparisonOp(interface, index, binary, invertToken);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Rewrite
|
||||||
|
!a && !b
|
||||||
|
|
||||||
|
As
|
||||||
|
!(a || b)
|
||||||
|
|
||||||
|
Activates on: &&
|
||||||
|
*/
|
||||||
|
class RewriteLogicalAnd : public CppQuickFixFactory
|
||||||
|
{
|
||||||
|
#ifdef WITH_TESTS
|
||||||
|
public:
|
||||||
|
static QObject *createTest() { return new QObject; }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override
|
||||||
|
{
|
||||||
|
BinaryExpressionAST *expression = nullptr;
|
||||||
|
const QList<AST *> &path = interface.path();
|
||||||
|
CppRefactoringFilePtr file = interface.currentFile();
|
||||||
|
|
||||||
|
int index = path.size() - 1;
|
||||||
|
for (; index != -1; --index) {
|
||||||
|
expression = path.at(index)->asBinaryExpression();
|
||||||
|
if (expression)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!expression)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!interface.isCursorOn(expression->binary_op_token))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QSharedPointer<RewriteLogicalAndOp> op(new RewriteLogicalAndOp(interface));
|
||||||
|
|
||||||
|
ASTMatcher matcher;
|
||||||
|
|
||||||
|
if (expression->match(op->pattern, &matcher) &&
|
||||||
|
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)) {
|
||||||
|
op->setDescription(Tr::tr("Rewrite Condition Using ||"));
|
||||||
|
op->setPriority(index);
|
||||||
|
result.append(op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void registerLogicalOperationQuickfixes()
|
||||||
|
{
|
||||||
|
CppQuickFixFactory::registerFactory<FlipLogicalOperands>();
|
||||||
|
CppQuickFixFactory::registerFactory<InverseLogicalComparison>();
|
||||||
|
CppQuickFixFactory::registerFactory<RewriteLogicalAnd>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace CppEditor::Internal
|
@@ -0,0 +1,8 @@
|
|||||||
|
// Copyright (C) 2024 The Qt Company Ltd.
|
||||||
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace CppEditor::Internal {
|
||||||
|
void registerLogicalOperationQuickfixes();
|
||||||
|
} // namespace CppEditor::Internal
|
Reference in New Issue
Block a user