From 0ebb004d8510b9c28fd0faab4f5ba53c490c28bd Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 27 Oct 2020 11:07:50 +0100 Subject: CppEditor: Make "Complete Switch" quickfix work with enum classes Fixes: QTCREATORBUG-20475 Change-Id: Id21a007ab4b652dcfe49d97bfa4c9fa77bacf8c4 Reviewed-by: Christian Stenger --- src/plugins/cppeditor/cppquickfix_test.cpp | 249 +++++++++++++++++++++++++++++ src/plugins/cppeditor/cppquickfixes.cpp | 7 +- 2 files changed, 255 insertions(+), 1 deletion(-) diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index e5257df4c0..b45fe7e911 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -373,6 +373,32 @@ void CppEditorPlugin::test_quickfix_data() "}\n" ); + // Same as above for enum class. + QTest::newRow("CompleteSwitchCaseStatement_basic1_enum class") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( + "enum class EnumType { V1, V2 };\n" + "\n" + "void f()\n" + "{\n" + " EnumType t;\n" + " @switch (t) {\n" + " }\n" + "}\n" + ) << _( + "enum class EnumType { V1, V2 };\n" + "\n" + "void f()\n" + "{\n" + " EnumType t;\n" + " switch (t) {\n" + " case EnumType::V1:\n" + " break;\n" + " case EnumType::V2:\n" + " break;\n" + " }\n" + "}\n" + ); + // Checks: All enum values are added as case statements for a blank switch when // the variable is declared alongside the enum definition. QTest::newRow("CompleteSwitchCaseStatement_basic1_enum_with_declaration") @@ -398,6 +424,30 @@ void CppEditorPlugin::test_quickfix_data() "}\n" ); + // Same as above for enum class. + QTest::newRow("CompleteSwitchCaseStatement_basic1_enum_with_declaration_enumClass") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( + "enum class EnumType { V1, V2 } t;\n" + "\n" + "void f()\n" + "{\n" + " @switch (t) {\n" + " }\n" + "}\n" + ) << _( + "enum class EnumType { V1, V2 } t;\n" + "\n" + "void f()\n" + "{\n" + " switch (t) {\n" + " case EnumType::V1:\n" + " break;\n" + " case EnumType::V2:\n" + " break;\n" + " }\n" + "}\n" + ); + // Checks: All enum values are added as case statements for a blank switch // for anonymous enums. QTest::newRow("CompleteSwitchCaseStatement_basic1_anonymous_enum") @@ -453,6 +503,36 @@ void CppEditorPlugin::test_quickfix_data() "}\n" ); + // Same as above for enum class. + QTest::newRow("CompleteSwitchCaseStatement_basic2_enumClass") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( + "enum class EnumType { V1, V2 };\n" + "\n" + "void f()\n" + "{\n" + " EnumType t;\n" + " @switch (t) {\n" + " default:\n" + " break;\n" + " }\n" + "}\n" + ) << _( + "enum class EnumType { V1, V2 };\n" + "\n" + "void f()\n" + "{\n" + " EnumType t;\n" + " switch (t) {\n" + " case EnumType::V1:\n" + " break;\n" + " case EnumType::V2:\n" + " break;\n" + " default:\n" + " break;\n" + " }\n" + "}\n" + ); + // Checks: Enum type in class is found. QTest::newRow("CompleteSwitchCaseStatement_enumTypeInClass") << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( @@ -475,6 +555,28 @@ void CppEditorPlugin::test_quickfix_data() "}\n" ); + // Same as above for enum class. + QTest::newRow("CompleteSwitchCaseStatement_enumClassInClass") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( + "struct C { enum class EnumType { V1, V2 }; };\n" + "\n" + "void f(C::EnumType t) {\n" + " @switch (t) {\n" + " }\n" + "}\n" + ) << _( + "struct C { enum class EnumType { V1, V2 }; };\n" + "\n" + "void f(C::EnumType t) {\n" + " switch (t) {\n" + " case C::EnumType::V1:\n" + " break;\n" + " case C::EnumType::V2:\n" + " break;\n" + " }\n" + "}\n" + ); + // Checks: Enum type in namespace is found. QTest::newRow("CompleteSwitchCaseStatement_enumTypeInNamespace") << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( @@ -497,6 +599,28 @@ void CppEditorPlugin::test_quickfix_data() "}\n" ); + // Same as above for enum class. + QTest::newRow("CompleteSwitchCaseStatement_enumClassInNamespace") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( + "namespace N { enum class EnumType { V1, V2 }; };\n" + "\n" + "void f(N::EnumType t) {\n" + " @switch (t) {\n" + " }\n" + "}\n" + ) << _( + "namespace N { enum class EnumType { V1, V2 }; };\n" + "\n" + "void f(N::EnumType t) {\n" + " switch (t) {\n" + " case N::EnumType::V1:\n" + " break;\n" + " case N::EnumType::V2:\n" + " break;\n" + " }\n" + "}\n" + ); + // Checks: The missing enum value is added. QTest::newRow("CompleteSwitchCaseStatement_oneValueMissing") << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( @@ -529,6 +653,38 @@ void CppEditorPlugin::test_quickfix_data() "}\n" ); + // Checks: Same as above for enum class. + QTest::newRow("CompleteSwitchCaseStatement_oneValueMissing_enumClass") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( + "enum class EnumType { V1, V2 };\n" + "\n" + "void f()\n" + "{\n" + " EnumType t;\n" + " @switch (t) {\n" + " case EnumType::V2:\n" + " break;\n" + " default:\n" + " break;\n" + " }\n" + "}\n" + ) << _( + "enum class EnumType { V1, V2 };\n" + "\n" + "void f()\n" + "{\n" + " EnumType t;\n" + " switch (t) {\n" + " case EnumType::V1:\n" + " break;\n" + " case EnumType::V2:\n" + " break;\n" + " default:\n" + " break;\n" + " }\n" + "}\n" + ); + // Checks: Find the correct enum type despite there being a declaration with the same name. QTest::newRow("CompleteSwitchCaseStatement_QTCREATORBUG10366_1") << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( @@ -553,6 +709,30 @@ void CppEditorPlugin::test_quickfix_data() "}\n" ); + // Same as above for enum class. + QTest::newRow("CompleteSwitchCaseStatement_QTCREATORBUG10366_1_enumClass") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( + "enum class test { TEST_1, TEST_2 };\n" + "\n" + "void f() {\n" + " enum test test;\n" + " @switch (test) {\n" + " }\n" + "}\n" + ) << _( + "enum class test { TEST_1, TEST_2 };\n" + "\n" + "void f() {\n" + " enum test test;\n" + " switch (test) {\n" + " case test::TEST_1:\n" + " break;\n" + " case test::TEST_2:\n" + " break;\n" + " }\n" + "}\n" + ); + // Checks: Find the correct enum type despite there being a declaration with the same name. QTest::newRow("CompleteSwitchCaseStatement_QTCREATORBUG10366_2") << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( @@ -581,6 +761,34 @@ void CppEditorPlugin::test_quickfix_data() "}\n" ); + // Same as above for enum class. + QTest::newRow("CompleteSwitchCaseStatement_QTCREATORBUG10366_2_enumClass") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( + "enum class test1 { Wrong11, Wrong12 };\n" + "enum class test { Right1, Right2 };\n" + "enum class test2 { Wrong21, Wrong22 };\n" + "\n" + "int main() {\n" + " enum test test;\n" + " @switch (test) {\n" + " }\n" + "}\n" + ) << _( + "enum class test1 { Wrong11, Wrong12 };\n" + "enum class test { Right1, Right2 };\n" + "enum class test2 { Wrong21, Wrong22 };\n" + "\n" + "int main() {\n" + " enum test test;\n" + " switch (test) {\n" + " case test::Right1:\n" + " break;\n" + " case test::Right2:\n" + " break;\n" + " }\n" + "}\n" + ); + // Checks: Do not crash on incomplete case statetement. QTest::newRow("CompleteSwitchCaseStatement_doNotCrashOnIncompleteCase") << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( @@ -596,6 +804,21 @@ void CppEditorPlugin::test_quickfix_data() "" ); + // Same as above for enum class. + QTest::newRow("CompleteSwitchCaseStatement_doNotCrashOnIncompleteCase_enumClass") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( + "enum class E {};\n" + "void f(E o)\n" + "{\n" + " @switch (o)\n" + " {\n" + " case\n" + " }\n" + "}\n" + ) << _( + "" + ); + // Checks: complete switch statement where enum is goes via a template type parameter QTest::newRow("CompleteSwitchCaseStatement_QTCREATORBUG-24752") << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( @@ -622,6 +845,32 @@ void CppEditorPlugin::test_quickfix_data() "}\n" ); + // Same as above for enum class. + QTest::newRow("CompleteSwitchCaseStatement_QTCREATORBUG-24752_enumClass") + << CppQuickFixFactoryPtr(new CompleteSwitchCaseStatement) << _( + "enum class E {A, B};\n" + "template struct S {\n" + " static T theType() { return T(); }\n" + "};\n" + "int main() {\n" + " @switch (S::theType()) {\n" + " }\n" + "}\n" + ) << _( + "enum class E {A, B};\n" + "template struct S {\n" + " static T theType() { return T(); }\n" + "};\n" + "int main() {\n" + " switch (S::theType()) {\n" + " case E::A:\n" + " break;\n" + " case E::B:\n" + " break;\n" + " }\n" + "}\n" + ); + // Checks: // 1. If the name does not start with ("m_" or "_") and does not // end with "_", we are forced to prefix the getter with "get". diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 2265d2ea5c..a59f2c18f2 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -2740,7 +2740,12 @@ static Enum *findEnum(const QList &results, const LookupContext &ctx return e; if (const NamedType *namedType = type->asNamedType()) { if (ClassOrNamespace *con = ctxt.lookupType(namedType->name(), result.scope())) { - const QList enums = con->unscopedEnums(); + QList enums = con->unscopedEnums(); + const QList symbols = con->symbols(); + for (Symbol * const s : symbols) { + if (const auto e = s->asEnum()) + enums << e; + } const Name *referenceName = namedType->name(); if (const QualifiedNameId *qualifiedName = referenceName->asQualifiedNameId()) referenceName = qualifiedName->name(); -- cgit v1.2.3