forked from qt-creator/qt-creator
CppEditor: Move control statement quickfixes into dedicated files
Change-Id: Ie4fb4bb466c151cc7666aecb5307fee6f6fd56d8 Reviewed-by: Christian Stenger <christian.stenger@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -115,6 +115,7 @@ add_qtc_plugin(CppEditor
|
|||||||
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
|
||||||
|
quickfixes/rewritecontrolstatements.cpp quickfixes/rewritecontrolstatements.h
|
||||||
resourcepreviewhoverhandler.cpp resourcepreviewhoverhandler.h
|
resourcepreviewhoverhandler.cpp resourcepreviewhoverhandler.h
|
||||||
searchsymbols.cpp searchsymbols.h
|
searchsymbols.cpp searchsymbols.h
|
||||||
semantichighlighter.cpp semantichighlighter.h
|
semantichighlighter.cpp semantichighlighter.h
|
||||||
|
@@ -259,6 +259,8 @@ QtcPlugin {
|
|||||||
"movefunctiondefinition.h",
|
"movefunctiondefinition.h",
|
||||||
"removeusingnamespace.cpp",
|
"removeusingnamespace.cpp",
|
||||||
"removeusingnamespace.h",
|
"removeusingnamespace.h",
|
||||||
|
"rewritecontrolstatements.cpp",
|
||||||
|
"rewritecontrolstatements.h",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -841,110 +841,6 @@ void QuickfixTest::testGeneric_data()
|
|||||||
"};\n"
|
"};\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
QTest::newRow("MoveDeclarationOutOfIf_ifOnly")
|
|
||||||
<< CppQuickFixFactoryPtr(new MoveDeclarationOutOfIf) << _(
|
|
||||||
"void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" if (Foo *@foo = g())\n"
|
|
||||||
" h();\n"
|
|
||||||
"}\n"
|
|
||||||
) << _(
|
|
||||||
"void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" Foo *foo = g();\n"
|
|
||||||
" if (foo)\n"
|
|
||||||
" h();\n"
|
|
||||||
"}\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
QTest::newRow("MoveDeclarationOutOfIf_ifElse")
|
|
||||||
<< CppQuickFixFactoryPtr(new MoveDeclarationOutOfIf) << _(
|
|
||||||
"void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" if (Foo *@foo = g())\n"
|
|
||||||
" h();\n"
|
|
||||||
" else\n"
|
|
||||||
" i();\n"
|
|
||||||
"}\n"
|
|
||||||
) << _(
|
|
||||||
"void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" Foo *foo = g();\n"
|
|
||||||
" if (foo)\n"
|
|
||||||
" h();\n"
|
|
||||||
" else\n"
|
|
||||||
" i();\n"
|
|
||||||
"}\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
QTest::newRow("MoveDeclarationOutOfIf_ifElseIf")
|
|
||||||
<< CppQuickFixFactoryPtr(new MoveDeclarationOutOfIf) << _(
|
|
||||||
"void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" if (Foo *foo = g()) {\n"
|
|
||||||
" if (Bar *@bar = x()) {\n"
|
|
||||||
" h();\n"
|
|
||||||
" j();\n"
|
|
||||||
" }\n"
|
|
||||||
" } else {\n"
|
|
||||||
" i();\n"
|
|
||||||
" }\n"
|
|
||||||
"}\n"
|
|
||||||
) << _(
|
|
||||||
"void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" if (Foo *foo = g()) {\n"
|
|
||||||
" Bar *bar = x();\n"
|
|
||||||
" if (bar) {\n"
|
|
||||||
" h();\n"
|
|
||||||
" j();\n"
|
|
||||||
" }\n"
|
|
||||||
" } else {\n"
|
|
||||||
" i();\n"
|
|
||||||
" }\n"
|
|
||||||
"}\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
QTest::newRow("MoveDeclarationOutOfWhile_singleWhile")
|
|
||||||
<< CppQuickFixFactoryPtr(new MoveDeclarationOutOfWhile) << _(
|
|
||||||
"void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" while (Foo *@foo = g())\n"
|
|
||||||
" j();\n"
|
|
||||||
"}\n"
|
|
||||||
) << _(
|
|
||||||
"void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" Foo *foo;\n"
|
|
||||||
" while ((foo = g()) != 0)\n"
|
|
||||||
" j();\n"
|
|
||||||
"}\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
QTest::newRow("MoveDeclarationOutOfWhile_whileInWhile")
|
|
||||||
<< CppQuickFixFactoryPtr(new MoveDeclarationOutOfWhile) << _(
|
|
||||||
"void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" while (Foo *foo = g()) {\n"
|
|
||||||
" while (Bar *@bar = h()) {\n"
|
|
||||||
" i();\n"
|
|
||||||
" j();\n"
|
|
||||||
" }\n"
|
|
||||||
" }\n"
|
|
||||||
"}\n"
|
|
||||||
) << _(
|
|
||||||
"void f()\n"
|
|
||||||
"{\n"
|
|
||||||
" while (Foo *foo = g()) {\n"
|
|
||||||
" Bar *bar;\n"
|
|
||||||
" while ((bar = h()) != 0) {\n"
|
|
||||||
" i();\n"
|
|
||||||
" j();\n"
|
|
||||||
" }\n"
|
|
||||||
" }\n"
|
|
||||||
"}\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check: Just a basic test since the main functionality is tested in
|
// Check: Just a basic test since the main functionality is tested in
|
||||||
// cpppointerdeclarationformatter_test.cpp
|
// cpppointerdeclarationformatter_test.cpp
|
||||||
QTest::newRow("ReformatPointerDeclaration")
|
QTest::newRow("ReformatPointerDeclaration")
|
||||||
@@ -1184,60 +1080,6 @@ void QuickfixTest::testGeneric_data()
|
|||||||
"};\n"
|
"};\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check: optimize postcrement
|
|
||||||
QTest::newRow("OptimizeForLoop_postcrement")
|
|
||||||
<< CppQuickFixFactoryPtr(new OptimizeForLoop)
|
|
||||||
<< _("void foo() {f@or (int i = 0; i < 3; i++) {}}\n")
|
|
||||||
<< _("void foo() {for (int i = 0; i < 3; ++i) {}}\n");
|
|
||||||
|
|
||||||
// Check: optimize condition
|
|
||||||
QTest::newRow("OptimizeForLoop_condition")
|
|
||||||
<< CppQuickFixFactoryPtr(new OptimizeForLoop)
|
|
||||||
<< _("void foo() {f@or (int i = 0; i < 3 + 5; ++i) {}}\n")
|
|
||||||
<< _("void foo() {for (int i = 0, total = 3 + 5; i < total; ++i) {}}\n");
|
|
||||||
|
|
||||||
// Check: optimize fliped condition
|
|
||||||
QTest::newRow("OptimizeForLoop_flipedCondition")
|
|
||||||
<< CppQuickFixFactoryPtr(new OptimizeForLoop)
|
|
||||||
<< _("void foo() {f@or (int i = 0; 3 + 5 > i; ++i) {}}\n")
|
|
||||||
<< _("void foo() {for (int i = 0, total = 3 + 5; total > i; ++i) {}}\n");
|
|
||||||
|
|
||||||
// Check: if "total" used, create other name.
|
|
||||||
QTest::newRow("OptimizeForLoop_alterVariableName")
|
|
||||||
<< CppQuickFixFactoryPtr(new OptimizeForLoop)
|
|
||||||
<< _("void foo() {f@or (int i = 0, total = 0; i < 3 + 5; ++i) {}}\n")
|
|
||||||
<< _("void foo() {for (int i = 0, total = 0, totalX = 3 + 5; i < totalX; ++i) {}}\n");
|
|
||||||
|
|
||||||
// Check: optimize postcrement and condition
|
|
||||||
QTest::newRow("OptimizeForLoop_optimizeBoth")
|
|
||||||
<< CppQuickFixFactoryPtr(new OptimizeForLoop)
|
|
||||||
<< _("void foo() {f@or (int i = 0; i < 3 + 5; i++) {}}\n")
|
|
||||||
<< _("void foo() {for (int i = 0, total = 3 + 5; i < total; ++i) {}}\n");
|
|
||||||
|
|
||||||
// Check: empty initializier
|
|
||||||
QTest::newRow("OptimizeForLoop_emptyInitializer")
|
|
||||||
<< CppQuickFixFactoryPtr(new OptimizeForLoop)
|
|
||||||
<< _("int i; void foo() {f@or (; i < 3 + 5; ++i) {}}\n")
|
|
||||||
<< _("int i; void foo() {for (int total = 3 + 5; i < total; ++i) {}}\n");
|
|
||||||
|
|
||||||
// Check: wrong initializier type -> no trigger
|
|
||||||
QTest::newRow("OptimizeForLoop_wrongInitializer")
|
|
||||||
<< CppQuickFixFactoryPtr(new OptimizeForLoop)
|
|
||||||
<< _("int i; void foo() {f@or (double a = 0; i < 3 + 5; ++i) {}}\n")
|
|
||||||
<< _();
|
|
||||||
|
|
||||||
// Check: No trigger when numeric
|
|
||||||
QTest::newRow("OptimizeForLoop_noTriggerNumeric1")
|
|
||||||
<< CppQuickFixFactoryPtr(new OptimizeForLoop)
|
|
||||||
<< _("void foo() {fo@r (int i = 0; i < 3; ++i) {}}\n")
|
|
||||||
<< _();
|
|
||||||
|
|
||||||
// Check: No trigger when numeric
|
|
||||||
QTest::newRow("OptimizeForLoop_noTriggerNumeric2")
|
|
||||||
<< CppQuickFixFactoryPtr(new OptimizeForLoop)
|
|
||||||
<< _("void foo() {fo@r (int i = 0; i < -3; ++i) {}}\n")
|
|
||||||
<< _();
|
|
||||||
|
|
||||||
QTest::newRow("ConvertFromPointer")
|
QTest::newRow("ConvertFromPointer")
|
||||||
<< CppQuickFixFactoryPtr(new ConvertFromAndToPointer)
|
<< CppQuickFixFactoryPtr(new ConvertFromAndToPointer)
|
||||||
<< _("void foo() {\n"
|
<< _("void foo() {\n"
|
||||||
@@ -1899,399 +1741,6 @@ void QuickfixTest::testExtractLiteralAsParameterNotTriggeringForInvalidCode()
|
|||||||
QuickFixOperationTest(testDocuments, &factory);
|
QuickFixOperationTest(testDocuments, &factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QuickfixTest::testAddCurlyBraces_data()
|
|
||||||
{
|
|
||||||
QTest::addColumn<QByteArray>("original");
|
|
||||||
QTest::addColumn<QByteArray>("expected");
|
|
||||||
|
|
||||||
QByteArray original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (true)
|
|
||||||
emit mySig();
|
|
||||||
})delim";
|
|
||||||
QByteArray expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
if (true) {
|
|
||||||
emit mySig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("if") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (true)
|
|
||||||
emit mySig();
|
|
||||||
else
|
|
||||||
emit otherSig();
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (true) {
|
|
||||||
emit mySig();
|
|
||||||
} else {
|
|
||||||
emit otherSig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("if with one else, unbraced") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (true) {
|
|
||||||
emit mySig();
|
|
||||||
} else
|
|
||||||
emit otherSig();
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (true) {
|
|
||||||
emit mySig();
|
|
||||||
} else {
|
|
||||||
emit otherSig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("if with one else, if braced") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (true)
|
|
||||||
emit mySig();
|
|
||||||
else {
|
|
||||||
emit otherSig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (true) {
|
|
||||||
emit mySig();
|
|
||||||
} else {
|
|
||||||
emit otherSig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("if with one else, else braced") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (true) {
|
|
||||||
emit mySig();
|
|
||||||
} else {
|
|
||||||
emit otherSig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
expected.clear();
|
|
||||||
QTest::newRow("if with one else, both braced") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (x == 1)
|
|
||||||
emit sig1();
|
|
||||||
else if (x == 2)
|
|
||||||
emit sig2();
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
if (x == 1) {
|
|
||||||
emit sig1();
|
|
||||||
} else if (x == 2) {
|
|
||||||
emit sig2();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("if-else chain without final else, unbraced") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (x == 1) {
|
|
||||||
emit sig1();
|
|
||||||
} else if (x == 2)
|
|
||||||
emit sig2();
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
if (x == 1) {
|
|
||||||
emit sig1();
|
|
||||||
} else if (x == 2) {
|
|
||||||
emit sig2();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("if-else chain without final else, partially braced 1") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (x == 1)
|
|
||||||
emit sig1();
|
|
||||||
else if (x == 2) {
|
|
||||||
emit sig2();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
if (x == 1) {
|
|
||||||
emit sig1();
|
|
||||||
} else if (x == 2) {
|
|
||||||
emit sig2();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("if-else chain without final else, partially braced 2") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (x == 1) {
|
|
||||||
emit sig1();
|
|
||||||
} else if (x == 2) {
|
|
||||||
emit sig2();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
expected.clear();
|
|
||||||
QTest::newRow("if-else chain without final else, fully braced") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (x == 1)
|
|
||||||
emit sig1();
|
|
||||||
else if (x == 2)
|
|
||||||
emit sig2();
|
|
||||||
else if (x == 3)
|
|
||||||
emit sig3();
|
|
||||||
else
|
|
||||||
emit otherSig();
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
if (x == 1) {
|
|
||||||
emit sig1();
|
|
||||||
} else if (x == 2) {
|
|
||||||
emit sig2();
|
|
||||||
} else if (x == 3) {
|
|
||||||
emit sig3();
|
|
||||||
} else {
|
|
||||||
emit otherSig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("if-else chain, unbraced") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (x == 1) {
|
|
||||||
emit sig1();
|
|
||||||
} else if (x == 2)
|
|
||||||
emit sig2();
|
|
||||||
else if (x == 3)
|
|
||||||
emit sig3();
|
|
||||||
else
|
|
||||||
emit otherSig();
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
if (x == 1) {
|
|
||||||
emit sig1();
|
|
||||||
} else if (x == 2) {
|
|
||||||
emit sig2();
|
|
||||||
} else if (x == 3) {
|
|
||||||
emit sig3();
|
|
||||||
} else {
|
|
||||||
emit otherSig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("if-else chain, partially braced 1") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (x == 1)
|
|
||||||
emit sig1();
|
|
||||||
else if (x == 2) {
|
|
||||||
emit sig2();
|
|
||||||
} else if (x == 3)
|
|
||||||
emit sig3();
|
|
||||||
else
|
|
||||||
emit otherSig();
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
if (x == 1) {
|
|
||||||
emit sig1();
|
|
||||||
} else if (x == 2) {
|
|
||||||
emit sig2();
|
|
||||||
} else if (x == 3) {
|
|
||||||
emit sig3();
|
|
||||||
} else {
|
|
||||||
emit otherSig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("if-else chain, partially braced 2") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (x == 1)
|
|
||||||
emit sig1();
|
|
||||||
else if (x == 2)
|
|
||||||
emit sig2();
|
|
||||||
else if (x == 3) {
|
|
||||||
emit sig3();
|
|
||||||
} else
|
|
||||||
emit otherSig();
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
if (x == 1) {
|
|
||||||
emit sig1();
|
|
||||||
} else if (x == 2) {
|
|
||||||
emit sig2();
|
|
||||||
} else if (x == 3) {
|
|
||||||
emit sig3();
|
|
||||||
} else {
|
|
||||||
emit otherSig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("if-else chain, partially braced 3") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (x == 1)
|
|
||||||
emit sig1();
|
|
||||||
else if (x == 2)
|
|
||||||
emit sig2();
|
|
||||||
else if (x == 3)
|
|
||||||
emit sig3();
|
|
||||||
else {
|
|
||||||
emit otherSig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
if (x == 1) {
|
|
||||||
emit sig1();
|
|
||||||
} else if (x == 2) {
|
|
||||||
emit sig2();
|
|
||||||
} else if (x == 3) {
|
|
||||||
emit sig3();
|
|
||||||
} else {
|
|
||||||
emit otherSig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("if-else chain, partially braced 4") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@if (x == 1) {
|
|
||||||
emit sig1();
|
|
||||||
} else if (x == 2) {
|
|
||||||
emit sig2();
|
|
||||||
} else if (x == 3) {
|
|
||||||
emit sig3();
|
|
||||||
} else {
|
|
||||||
emit otherSig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
expected.clear();
|
|
||||||
QTest::newRow("if-else chain, fully braced") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@while (true)
|
|
||||||
emit mySig();
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
while (true) {
|
|
||||||
emit mySig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("while") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@for (int i = 0; i < 10; ++i)
|
|
||||||
emit mySig();
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 10; ++i) {
|
|
||||||
emit mySig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("for") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@for (int i : list)
|
|
||||||
emit mySig();
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
for (int i : list) {
|
|
||||||
emit mySig();
|
|
||||||
}
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("range-based for") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@do
|
|
||||||
emit mySig();
|
|
||||||
while (true);
|
|
||||||
})delim";
|
|
||||||
expected = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
emit mySig();
|
|
||||||
} while (true);
|
|
||||||
})delim";
|
|
||||||
QTest::newRow("do") << original << expected;
|
|
||||||
|
|
||||||
original = R"delim(
|
|
||||||
void MyObject::f()
|
|
||||||
{
|
|
||||||
@do {
|
|
||||||
emit mySig();
|
|
||||||
} while (true);
|
|
||||||
})delim";
|
|
||||||
expected.clear();
|
|
||||||
QTest::newRow("already has braces") << original << expected;
|
|
||||||
}
|
|
||||||
|
|
||||||
void QuickfixTest::testAddCurlyBraces()
|
|
||||||
{
|
|
||||||
QFETCH(QByteArray, original);
|
|
||||||
QFETCH(QByteArray, expected);
|
|
||||||
|
|
||||||
AddBracesToControlStatement factory;
|
|
||||||
QuickFixOperationTest({CppTestDocument::create("file.cpp", original, expected)}, &factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
void QuickfixTest::testChangeCommentType_data()
|
void QuickfixTest::testChangeCommentType_data()
|
||||||
{
|
{
|
||||||
QTest::addColumn<QString>("input");
|
QTest::addColumn<QString>("input");
|
||||||
|
@@ -108,9 +108,6 @@ private slots:
|
|||||||
void testExtractLiteralAsParameterMemberFunctionSeparateFiles();
|
void testExtractLiteralAsParameterMemberFunctionSeparateFiles();
|
||||||
void testExtractLiteralAsParameterNotTriggeringForInvalidCode();
|
void testExtractLiteralAsParameterNotTriggeringForInvalidCode();
|
||||||
|
|
||||||
void testAddCurlyBraces_data();
|
|
||||||
void testAddCurlyBraces();
|
|
||||||
|
|
||||||
void testChangeCommentType_data();
|
void testChangeCommentType_data();
|
||||||
void testChangeCommentType();
|
void testChangeCommentType();
|
||||||
|
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
#include "moveclasstoownfile.h"
|
#include "moveclasstoownfile.h"
|
||||||
#include "movefunctiondefinition.h"
|
#include "movefunctiondefinition.h"
|
||||||
#include "removeusingnamespace.h"
|
#include "removeusingnamespace.h"
|
||||||
|
#include "rewritecontrolstatements.h"
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/messagemanager.h>
|
#include <coreplugin/messagemanager.h>
|
||||||
@@ -237,430 +238,6 @@ void SplitSimpleDeclaration::doMatch(const CppQuickFixInterface &interface,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
template<typename Statement> Statement *asControlStatement(AST *node)
|
|
||||||
{
|
|
||||||
if constexpr (std::is_same_v<Statement, IfStatementAST>)
|
|
||||||
return node->asIfStatement();
|
|
||||||
if constexpr (std::is_same_v<Statement, WhileStatementAST>)
|
|
||||||
return node->asWhileStatement();
|
|
||||||
if constexpr (std::is_same_v<Statement, ForStatementAST>)
|
|
||||||
return node->asForStatement();
|
|
||||||
if constexpr (std::is_same_v<Statement, RangeBasedForStatementAST>)
|
|
||||||
return node->asRangeBasedForStatement();
|
|
||||||
if constexpr (std::is_same_v<Statement, DoStatementAST>)
|
|
||||||
return node->asDoStatement();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Statement>
|
|
||||||
int triggerToken(const Statement *statement)
|
|
||||||
{
|
|
||||||
if constexpr (std::is_same_v<Statement, IfStatementAST>)
|
|
||||||
return statement->if_token;
|
|
||||||
if constexpr (std::is_same_v<Statement, WhileStatementAST>)
|
|
||||||
return statement->while_token;
|
|
||||||
if constexpr (std::is_same_v<Statement, DoStatementAST>)
|
|
||||||
return statement->do_token;
|
|
||||||
if constexpr (std::is_same_v<Statement, ForStatementAST>
|
|
||||||
|| std::is_same_v<Statement, RangeBasedForStatementAST>) {
|
|
||||||
return statement->for_token;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Statement>
|
|
||||||
int tokenToInsertOpeningBraceAfter(const Statement *statement)
|
|
||||||
{
|
|
||||||
if constexpr (std::is_same_v<Statement, DoStatementAST>)
|
|
||||||
return statement->do_token;
|
|
||||||
return statement->rparen_token;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Statement> class AddBracesToControlStatementOp : public CppQuickFixOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AddBracesToControlStatementOp(const CppQuickFixInterface &interface,
|
|
||||||
const QList<Statement *> &statements,
|
|
||||||
StatementAST *elseStatement,
|
|
||||||
int elseToken)
|
|
||||||
: CppQuickFixOperation(interface, 0)
|
|
||||||
, m_statements(statements), m_elseStatement(elseStatement), m_elseToken(elseToken)
|
|
||||||
{
|
|
||||||
setDescription(Tr::tr("Add Curly Braces"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void perform() override
|
|
||||||
{
|
|
||||||
CppRefactoringChanges refactoring(snapshot());
|
|
||||||
CppRefactoringFilePtr currentFile = refactoring.cppFile(filePath());
|
|
||||||
|
|
||||||
ChangeSet changes;
|
|
||||||
for (Statement * const statement : m_statements) {
|
|
||||||
const int start = currentFile->endOf(tokenToInsertOpeningBraceAfter(statement));
|
|
||||||
changes.insert(start, QLatin1String(" {"));
|
|
||||||
if constexpr (std::is_same_v<Statement, DoStatementAST>) {
|
|
||||||
const int end = currentFile->startOf(statement->while_token);
|
|
||||||
changes.insert(end, QLatin1String("} "));
|
|
||||||
} else if constexpr (std::is_same_v<Statement, IfStatementAST>) {
|
|
||||||
if (statement->else_statement) {
|
|
||||||
changes.insert(currentFile->startOf(statement->else_token), "} ");
|
|
||||||
} else {
|
|
||||||
changes.insert(currentFile->endOf(statement->statement->lastToken() - 1),
|
|
||||||
"\n}");
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
const int end = currentFile->endOf(statement->statement->lastToken() - 1);
|
|
||||||
changes.insert(end, QLatin1String("\n}"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (m_elseStatement) {
|
|
||||||
changes.insert(currentFile->endOf(m_elseToken), " {");
|
|
||||||
changes.insert(currentFile->endOf(m_elseStatement->lastToken() - 1), "\n}");
|
|
||||||
}
|
|
||||||
|
|
||||||
currentFile->setChangeSet(changes);
|
|
||||||
currentFile->apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const QList<Statement *> m_statements;
|
|
||||||
StatementAST * const m_elseStatement;
|
|
||||||
const int m_elseToken;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
template<typename Statement>
|
|
||||||
bool checkControlStatementsHelper(const CppQuickFixInterface &interface, QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
Statement * const statement = asControlStatement<Statement>(interface.path().last());
|
|
||||||
if (!statement)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QList<Statement *> statements;
|
|
||||||
if (interface.isCursorOn(triggerToken(statement)) && statement->statement
|
|
||||||
&& !statement->statement->asCompoundStatement()) {
|
|
||||||
statements << statement;
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementAST *elseStmt = nullptr;
|
|
||||||
int elseToken = 0;
|
|
||||||
if constexpr (std::is_same_v<Statement, IfStatementAST>) {
|
|
||||||
IfStatementAST *currentIfStmt = statement;
|
|
||||||
for (elseStmt = currentIfStmt->else_statement, elseToken = currentIfStmt->else_token;
|
|
||||||
elseStmt && (currentIfStmt = elseStmt->asIfStatement());
|
|
||||||
elseStmt = currentIfStmt->else_statement, elseToken = currentIfStmt->else_token) {
|
|
||||||
if (currentIfStmt->statement && !currentIfStmt->statement->asCompoundStatement())
|
|
||||||
statements << currentIfStmt;
|
|
||||||
}
|
|
||||||
if (elseStmt && (elseStmt->asIfStatement() || elseStmt->asCompoundStatement())) {
|
|
||||||
elseStmt = nullptr;
|
|
||||||
elseToken = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!statements.isEmpty() || elseStmt)
|
|
||||||
result << new AddBracesToControlStatementOp(interface, statements, elseStmt, elseToken);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename ...Statements>
|
|
||||||
void checkControlStatements(const CppQuickFixInterface &interface, QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
(... || checkControlStatementsHelper<Statements>(interface, result));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddBracesToControlStatement::doMatch(const CppQuickFixInterface &interface,
|
|
||||||
QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
if (interface.path().isEmpty())
|
|
||||||
return;
|
|
||||||
checkControlStatements<IfStatementAST,
|
|
||||||
WhileStatementAST,
|
|
||||||
ForStatementAST,
|
|
||||||
RangeBasedForStatementAST,
|
|
||||||
DoStatementAST>(interface, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class MoveDeclarationOutOfIfOp: public CppQuickFixOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MoveDeclarationOutOfIfOp(const CppQuickFixInterface &interface)
|
|
||||||
: CppQuickFixOperation(interface)
|
|
||||||
{
|
|
||||||
setDescription(Tr::tr("Move Declaration out of Condition"));
|
|
||||||
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
condition = mk.Condition();
|
|
||||||
pattern = mk.IfStatement(condition);
|
|
||||||
}
|
|
||||||
|
|
||||||
void perform() override
|
|
||||||
{
|
|
||||||
CppRefactoringChanges refactoring(snapshot());
|
|
||||||
CppRefactoringFilePtr currentFile = refactoring.cppFile(filePath());
|
|
||||||
|
|
||||||
ChangeSet changes;
|
|
||||||
|
|
||||||
changes.copy(currentFile->range(core), currentFile->startOf(condition));
|
|
||||||
|
|
||||||
int insertPos = currentFile->startOf(pattern);
|
|
||||||
changes.move(currentFile->range(condition), insertPos);
|
|
||||||
changes.insert(insertPos, QLatin1String(";\n"));
|
|
||||||
|
|
||||||
currentFile->setChangeSet(changes);
|
|
||||||
currentFile->apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASTMatcher matcher;
|
|
||||||
ASTPatternBuilder mk;
|
|
||||||
ConditionAST *condition = nullptr;
|
|
||||||
IfStatementAST *pattern = nullptr;
|
|
||||||
CoreDeclaratorAST *core = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void MoveDeclarationOutOfIf::doMatch(const CppQuickFixInterface &interface,
|
|
||||||
QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
const QList<AST *> &path = interface.path();
|
|
||||||
using Ptr = QSharedPointer<MoveDeclarationOutOfIfOp>;
|
|
||||||
Ptr op(new MoveDeclarationOutOfIfOp(interface));
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (interface.isCursorOn(op->core)) {
|
|
||||||
op->setPriority(index);
|
|
||||||
result.append(op);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
op->reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class MoveDeclarationOutOfWhileOp: public CppQuickFixOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MoveDeclarationOutOfWhileOp(const CppQuickFixInterface &interface)
|
|
||||||
: CppQuickFixOperation(interface)
|
|
||||||
{
|
|
||||||
setDescription(Tr::tr("Move Declaration out of Condition"));
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset()
|
|
||||||
{
|
|
||||||
condition = mk.Condition();
|
|
||||||
pattern = mk.WhileStatement(condition);
|
|
||||||
}
|
|
||||||
|
|
||||||
void perform() override
|
|
||||||
{
|
|
||||||
CppRefactoringChanges refactoring(snapshot());
|
|
||||||
CppRefactoringFilePtr currentFile = refactoring.cppFile(filePath());
|
|
||||||
|
|
||||||
ChangeSet changes;
|
|
||||||
|
|
||||||
changes.insert(currentFile->startOf(condition), QLatin1String("("));
|
|
||||||
changes.insert(currentFile->endOf(condition), QLatin1String(") != 0"));
|
|
||||||
|
|
||||||
int insertPos = currentFile->startOf(pattern);
|
|
||||||
const int conditionStart = currentFile->startOf(condition);
|
|
||||||
changes.move(conditionStart, currentFile->startOf(core), insertPos);
|
|
||||||
changes.copy(currentFile->range(core), insertPos);
|
|
||||||
changes.insert(insertPos, QLatin1String(";\n"));
|
|
||||||
|
|
||||||
currentFile->setChangeSet(changes);
|
|
||||||
currentFile->apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
ASTMatcher matcher;
|
|
||||||
ASTPatternBuilder mk;
|
|
||||||
ConditionAST *condition = nullptr;
|
|
||||||
WhileStatementAST *pattern = nullptr;
|
|
||||||
CoreDeclaratorAST *core = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void MoveDeclarationOutOfWhile::doMatch(const CppQuickFixInterface &interface,
|
|
||||||
QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
const QList<AST *> &path = interface.path();
|
|
||||||
QSharedPointer<MoveDeclarationOutOfWhileOp> op(new MoveDeclarationOutOfWhileOp(interface));
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (!declarator->equal_token)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!declarator->initializer)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (interface.isCursorOn(op->core)) {
|
|
||||||
op->setPriority(index);
|
|
||||||
result.append(op);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
op->reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class SplitIfStatementOp: public CppQuickFixOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SplitIfStatementOp(const CppQuickFixInterface &interface, int priority,
|
|
||||||
IfStatementAST *pattern, BinaryExpressionAST *condition)
|
|
||||||
: CppQuickFixOperation(interface, priority)
|
|
||||||
, pattern(pattern)
|
|
||||||
, condition(condition)
|
|
||||||
{
|
|
||||||
setDescription(Tr::tr("Split if Statement"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void perform() override
|
|
||||||
{
|
|
||||||
CppRefactoringChanges refactoring(snapshot());
|
|
||||||
CppRefactoringFilePtr currentFile = refactoring.cppFile(filePath());
|
|
||||||
|
|
||||||
const Token binaryToken = currentFile->tokenAt(condition->binary_op_token);
|
|
||||||
|
|
||||||
if (binaryToken.is(T_AMPER_AMPER))
|
|
||||||
splitAndCondition(currentFile);
|
|
||||||
else
|
|
||||||
splitOrCondition(currentFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
void splitAndCondition(CppRefactoringFilePtr currentFile) const
|
|
||||||
{
|
|
||||||
ChangeSet changes;
|
|
||||||
|
|
||||||
int startPos = currentFile->startOf(pattern);
|
|
||||||
changes.insert(startPos, QLatin1String("if ("));
|
|
||||||
changes.move(currentFile->range(condition->left_expression), startPos);
|
|
||||||
changes.insert(startPos, QLatin1String(") {\n"));
|
|
||||||
|
|
||||||
const int lExprEnd = currentFile->endOf(condition->left_expression);
|
|
||||||
changes.remove(lExprEnd, currentFile->startOf(condition->right_expression));
|
|
||||||
changes.insert(currentFile->endOf(pattern), QLatin1String("\n}"));
|
|
||||||
|
|
||||||
currentFile->setChangeSet(changes);
|
|
||||||
currentFile->apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
void splitOrCondition(CppRefactoringFilePtr currentFile) const
|
|
||||||
{
|
|
||||||
ChangeSet changes;
|
|
||||||
|
|
||||||
StatementAST *ifTrueStatement = pattern->statement;
|
|
||||||
CompoundStatementAST *compoundStatement = ifTrueStatement->asCompoundStatement();
|
|
||||||
|
|
||||||
int insertPos = currentFile->endOf(ifTrueStatement);
|
|
||||||
if (compoundStatement)
|
|
||||||
changes.insert(insertPos, QLatin1String(" "));
|
|
||||||
else
|
|
||||||
changes.insert(insertPos, QLatin1String("\n"));
|
|
||||||
changes.insert(insertPos, QLatin1String("else if ("));
|
|
||||||
|
|
||||||
const int rExprStart = currentFile->startOf(condition->right_expression);
|
|
||||||
changes.move(rExprStart, currentFile->startOf(pattern->rparen_token), insertPos);
|
|
||||||
changes.insert(insertPos, QLatin1String(")"));
|
|
||||||
|
|
||||||
const int rParenEnd = currentFile->endOf(pattern->rparen_token);
|
|
||||||
changes.copy(rParenEnd, currentFile->endOf(pattern->statement), insertPos);
|
|
||||||
|
|
||||||
const int lExprEnd = currentFile->endOf(condition->left_expression);
|
|
||||||
changes.remove(lExprEnd, currentFile->startOf(condition->right_expression));
|
|
||||||
|
|
||||||
currentFile->setChangeSet(changes);
|
|
||||||
currentFile->apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
IfStatementAST *pattern;
|
|
||||||
BinaryExpressionAST *condition;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void SplitIfStatement::doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
IfStatementAST *pattern = nullptr;
|
|
||||||
const QList<AST *> &path = interface.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;
|
|
||||||
|
|
||||||
unsigned splitKind = 0;
|
|
||||||
for (++index; index < path.size(); ++index) {
|
|
||||||
AST *node = path.at(index);
|
|
||||||
BinaryExpressionAST *condition = node->asBinaryExpression();
|
|
||||||
if (!condition)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Token binaryToken = interface.currentFile()->tokenAt(condition->binary_op_token);
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
// we can't reliably split &&s in ifs with an else branch
|
|
||||||
if (splitKind == T_AMPER_AMPER && pattern->else_statement)
|
|
||||||
return;
|
|
||||||
} else if (splitKind != binaryToken.kind()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (interface.isCursorOn(condition->binary_op_token)) {
|
|
||||||
result << new SplitIfStatementOp(interface, index, pattern, condition);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
class ConvertNumericLiteralOp: public CppQuickFixOperation
|
class ConvertNumericLiteralOp: public CppQuickFixOperation
|
||||||
@@ -2814,187 +2391,6 @@ void AssignToLocalVariable::doMatch(const CppQuickFixInterface &interface, Quick
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
class OptimizeForLoopOperation: public CppQuickFixOperation
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
OptimizeForLoopOperation(const CppQuickFixInterface &interface, const ForStatementAST *forAst,
|
|
||||||
const bool optimizePostcrement, const ExpressionAST *expression,
|
|
||||||
const FullySpecifiedType &type)
|
|
||||||
: CppQuickFixOperation(interface)
|
|
||||||
, m_forAst(forAst)
|
|
||||||
, m_optimizePostcrement(optimizePostcrement)
|
|
||||||
, m_expression(expression)
|
|
||||||
, m_type(type)
|
|
||||||
{
|
|
||||||
setDescription(Tr::tr("Optimize for-Loop"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void perform() override
|
|
||||||
{
|
|
||||||
QTC_ASSERT(m_forAst, return);
|
|
||||||
|
|
||||||
const Utils::FilePath filePath = currentFile()->filePath();
|
|
||||||
const CppRefactoringChanges refactoring(snapshot());
|
|
||||||
const CppRefactoringFilePtr file = refactoring.cppFile(filePath);
|
|
||||||
ChangeSet change;
|
|
||||||
|
|
||||||
// Optimize post (in|de)crement operator to pre (in|de)crement operator
|
|
||||||
if (m_optimizePostcrement && m_forAst->expression) {
|
|
||||||
PostIncrDecrAST *incrdecr = m_forAst->expression->asPostIncrDecr();
|
|
||||||
if (incrdecr && incrdecr->base_expression && incrdecr->incr_decr_token) {
|
|
||||||
change.flip(file->range(incrdecr->base_expression),
|
|
||||||
file->range(incrdecr->incr_decr_token));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimize Condition
|
|
||||||
int renamePos = -1;
|
|
||||||
if (m_expression) {
|
|
||||||
QString varName = QLatin1String("total");
|
|
||||||
|
|
||||||
if (file->textOf(m_forAst->initializer).length() == 1) {
|
|
||||||
Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview();
|
|
||||||
const QString typeAndName = oo.prettyType(m_type, varName);
|
|
||||||
renamePos = file->endOf(m_forAst->initializer) - 1 + typeAndName.length();
|
|
||||||
change.insert(file->endOf(m_forAst->initializer) - 1, // "-1" because of ";"
|
|
||||||
typeAndName + QLatin1String(" = ") + file->textOf(m_expression));
|
|
||||||
} else {
|
|
||||||
// Check if varName is already used
|
|
||||||
if (DeclarationStatementAST *ds = m_forAst->initializer->asDeclarationStatement()) {
|
|
||||||
if (DeclarationAST *decl = ds->declaration) {
|
|
||||||
if (SimpleDeclarationAST *sdecl = decl->asSimpleDeclaration()) {
|
|
||||||
for (;;) {
|
|
||||||
bool match = false;
|
|
||||||
for (DeclaratorListAST *it = sdecl->declarator_list; it;
|
|
||||||
it = it->next) {
|
|
||||||
if (file->textOf(it->value->core_declarator) == varName) {
|
|
||||||
varName += QLatin1Char('X');
|
|
||||||
match = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!match)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renamePos = file->endOf(m_forAst->initializer) + 1;
|
|
||||||
change.insert(file->endOf(m_forAst->initializer) - 1, // "-1" because of ";"
|
|
||||||
QLatin1String(", ") + varName + QLatin1String(" = ")
|
|
||||||
+ file->textOf(m_expression));
|
|
||||||
}
|
|
||||||
|
|
||||||
ChangeSet::Range exprRange(file->startOf(m_expression), file->endOf(m_expression));
|
|
||||||
change.replace(exprRange, varName);
|
|
||||||
}
|
|
||||||
|
|
||||||
file->setChangeSet(change);
|
|
||||||
file->apply();
|
|
||||||
|
|
||||||
// Select variable name and trigger symbol rename
|
|
||||||
if (renamePos != -1) {
|
|
||||||
QTextCursor c = file->cursor();
|
|
||||||
c.setPosition(renamePos);
|
|
||||||
editor()->setTextCursor(c);
|
|
||||||
editor()->renameSymbolUnderCursor();
|
|
||||||
c.select(QTextCursor::WordUnderCursor);
|
|
||||||
editor()->setTextCursor(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
const ForStatementAST *m_forAst;
|
|
||||||
const bool m_optimizePostcrement;
|
|
||||||
const ExpressionAST *m_expression;
|
|
||||||
const FullySpecifiedType m_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
void OptimizeForLoop::doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result)
|
|
||||||
{
|
|
||||||
const QList<AST *> path = interface.path();
|
|
||||||
ForStatementAST *forAst = nullptr;
|
|
||||||
if (!path.isEmpty())
|
|
||||||
forAst = path.last()->asForStatement();
|
|
||||||
if (!forAst || !interface.isCursorOn(forAst))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Check for optimizing a postcrement
|
|
||||||
const CppRefactoringFilePtr file = interface.currentFile();
|
|
||||||
bool optimizePostcrement = false;
|
|
||||||
if (forAst->expression) {
|
|
||||||
if (PostIncrDecrAST *incrdecr = forAst->expression->asPostIncrDecr()) {
|
|
||||||
const Token t = file->tokenAt(incrdecr->incr_decr_token);
|
|
||||||
if (t.is(T_PLUS_PLUS) || t.is(T_MINUS_MINUS))
|
|
||||||
optimizePostcrement = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for optimizing condition
|
|
||||||
bool optimizeCondition = false;
|
|
||||||
FullySpecifiedType conditionType;
|
|
||||||
ExpressionAST *conditionExpression = nullptr;
|
|
||||||
if (forAst->initializer && forAst->condition) {
|
|
||||||
if (BinaryExpressionAST *binary = forAst->condition->asBinaryExpression()) {
|
|
||||||
// Get the expression against which we should evaluate
|
|
||||||
IdExpressionAST *conditionId = binary->left_expression->asIdExpression();
|
|
||||||
if (conditionId) {
|
|
||||||
conditionExpression = binary->right_expression;
|
|
||||||
} else {
|
|
||||||
conditionId = binary->right_expression->asIdExpression();
|
|
||||||
conditionExpression = binary->left_expression;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (conditionId && conditionExpression
|
|
||||||
&& !(conditionExpression->asNumericLiteral()
|
|
||||||
|| conditionExpression->asStringLiteral()
|
|
||||||
|| conditionExpression->asIdExpression()
|
|
||||||
|| conditionExpression->asUnaryExpression())) {
|
|
||||||
// Determine type of for initializer
|
|
||||||
FullySpecifiedType initializerType;
|
|
||||||
if (DeclarationStatementAST *stmt = forAst->initializer->asDeclarationStatement()) {
|
|
||||||
if (stmt->declaration) {
|
|
||||||
if (SimpleDeclarationAST *decl = stmt->declaration->asSimpleDeclaration()) {
|
|
||||||
if (decl->symbols) {
|
|
||||||
if (Symbol *symbol = decl->symbols->value)
|
|
||||||
initializerType = symbol->type();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine type of for condition
|
|
||||||
TypeOfExpression typeOfExpression;
|
|
||||||
typeOfExpression.init(interface.semanticInfo().doc, interface.snapshot(),
|
|
||||||
interface.context().bindings());
|
|
||||||
typeOfExpression.setExpandTemplates(true);
|
|
||||||
Scope *scope = file->scopeAt(conditionId->firstToken());
|
|
||||||
const QList<LookupItem> conditionItems = typeOfExpression(
|
|
||||||
conditionId, interface.semanticInfo().doc, scope);
|
|
||||||
if (!conditionItems.isEmpty())
|
|
||||||
conditionType = conditionItems.first().type();
|
|
||||||
|
|
||||||
if (conditionType.isValid()
|
|
||||||
&& (file->textOf(forAst->initializer) == QLatin1String(";")
|
|
||||||
|| initializerType == conditionType)) {
|
|
||||||
optimizeCondition = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (optimizePostcrement || optimizeCondition) {
|
|
||||||
result << new OptimizeForLoopOperation(interface, forAst, optimizePostcrement,
|
|
||||||
optimizeCondition ? conditionExpression : nullptr,
|
|
||||||
conditionType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExtraRefactoringOperations::doMatch(const CppQuickFixInterface &interface,
|
void ExtraRefactoringOperations::doMatch(const CppQuickFixInterface &interface,
|
||||||
QuickFixOperations &result)
|
QuickFixOperations &result)
|
||||||
{
|
{
|
||||||
@@ -3569,13 +2965,8 @@ void createCppQuickFixes()
|
|||||||
|
|
||||||
new ConvertNumericLiteral;
|
new ConvertNumericLiteral;
|
||||||
|
|
||||||
new MoveDeclarationOutOfIf;
|
|
||||||
new MoveDeclarationOutOfWhile;
|
|
||||||
|
|
||||||
new SplitIfStatement;
|
|
||||||
new SplitSimpleDeclaration;
|
new SplitSimpleDeclaration;
|
||||||
|
|
||||||
new AddBracesToControlStatement;
|
|
||||||
new RearrangeParamDeclarationList;
|
new RearrangeParamDeclarationList;
|
||||||
new ReformatPointerDeclaration;
|
new ReformatPointerDeclaration;
|
||||||
|
|
||||||
@@ -3599,8 +2990,7 @@ void createCppQuickFixes()
|
|||||||
registerConvertStringLiteralQuickfixes();
|
registerConvertStringLiteralQuickfixes();
|
||||||
registerCreateDeclarationFromUseQuickfixes();
|
registerCreateDeclarationFromUseQuickfixes();
|
||||||
registerLogicalOperationQuickfixes();
|
registerLogicalOperationQuickfixes();
|
||||||
|
registerRewriteControlStatementQuickfixes();
|
||||||
new OptimizeForLoop;
|
|
||||||
|
|
||||||
new ExtraRefactoringOperations;
|
new ExtraRefactoringOperations;
|
||||||
|
|
||||||
|
@@ -70,67 +70,6 @@ private:
|
|||||||
const bool m_test;
|
const bool m_test;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
|
||||||
Replace
|
|
||||||
if (Type name = foo()) {...}
|
|
||||||
|
|
||||||
With
|
|
||||||
Type name = foo();
|
|
||||||
if (name) {...}
|
|
||||||
|
|
||||||
Activates on: the name of the introduced variable
|
|
||||||
*/
|
|
||||||
class MoveDeclarationOutOfIf: public CppQuickFixFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Replace
|
|
||||||
while (Type name = foo()) {...}
|
|
||||||
|
|
||||||
With
|
|
||||||
Type name;
|
|
||||||
while ((name = foo()) != 0) {...}
|
|
||||||
|
|
||||||
Activates on: the name of the introduced variable
|
|
||||||
*/
|
|
||||||
class MoveDeclarationOutOfWhile: public CppQuickFixFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Replace
|
|
||||||
if (something && something_else) {
|
|
||||||
}
|
|
||||||
|
|
||||||
with
|
|
||||||
if (something)
|
|
||||||
if (something_else) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
and
|
|
||||||
if (something || something_else)
|
|
||||||
x;
|
|
||||||
|
|
||||||
with
|
|
||||||
if (something)
|
|
||||||
x;
|
|
||||||
else if (something_else)
|
|
||||||
x;
|
|
||||||
|
|
||||||
Activates on: && or ||
|
|
||||||
*/
|
|
||||||
class SplitIfStatement: public CppQuickFixFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Rewrite
|
Rewrite
|
||||||
int *a, b;
|
int *a, b;
|
||||||
@@ -147,25 +86,6 @@ public:
|
|||||||
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override;
|
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
|
||||||
Add curly braces to a control statement that doesn't already contain a
|
|
||||||
compound statement. I.e.
|
|
||||||
|
|
||||||
if (a)
|
|
||||||
b;
|
|
||||||
becomes
|
|
||||||
if (a) {
|
|
||||||
b;
|
|
||||||
}
|
|
||||||
|
|
||||||
Activates on: the keyword
|
|
||||||
*/
|
|
||||||
class AddBracesToControlStatement : public CppQuickFixFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Switches places of the parameter declaration under cursor
|
Switches places of the parameter declaration under cursor
|
||||||
with the next or the previous one in the parameter declaration list
|
with the next or the previous one in the parameter declaration list
|
||||||
@@ -260,16 +180,6 @@ public:
|
|||||||
void doMatch(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) override;
|
void doMatch(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
|
||||||
Optimizes a for loop to avoid permanent condition check and forces to use preincrement
|
|
||||||
or predecrement operators in the expression of the for loop.
|
|
||||||
*/
|
|
||||||
class OptimizeForLoop : public CppQuickFixFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void doMatch(const CppQuickFixInterface &interface, TextEditor::QuickFixOperations &result) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Converts C-style to C++-style comments and vice versa
|
//! Converts C-style to C++-style comments and vice versa
|
||||||
class ConvertCommentStyle : public CppQuickFixFactory
|
class ConvertCommentStyle : public CppQuickFixFactory
|
||||||
{
|
{
|
||||||
|
1342
src/plugins/cppeditor/quickfixes/rewritecontrolstatements.cpp
Normal file
1342
src/plugins/cppeditor/quickfixes/rewritecontrolstatements.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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 registerRewriteControlStatementQuickfixes();
|
||||||
|
} // namespace CppEditor::Internal
|
Reference in New Issue
Block a user