diff --git a/plugins/clang/codecompletion/context.cpp b/plugins/clang/codecompletion/context.cpp --- a/plugins/clang/codecompletion/context.cpp +++ b/plugins/clang/codecompletion/context.cpp @@ -27,6 +27,8 @@ #include #include +#include +#include #include #include @@ -46,6 +48,8 @@ #include #include #include +#include +#include #include "../util/clangdebug.h" #include "../util/clangtypes.h" @@ -172,7 +176,29 @@ void execute(KTextEditor::View* view, const KTextEditor::Range& word) override { - view->document()->replaceText(word, m_returnType + QLatin1Char(' ') + m_display.replace(QRegularExpression(QStringLiteral("\\s*=\\s*0")), QString()) + QLatin1String(" override;")); + QString replacement = m_returnType + QLatin1Char(' ') + m_display.replace(QRegularExpression(QStringLiteral("\\s*=\\s*0")), QString()); + + bool appendSpecifer = true; + if (const auto* project = + KDevelop::ICore::self()->projectController()->findProjectForUrl(view->document()->url())) { + const auto arguments = KDevelop::IDefinesAndIncludesManager::manager()->parserArguments( + project->filesForPath(IndexedString(view->document()->url().path())).first()); + const auto match = QRegularExpression(QStringLiteral(R"(-std=c\+\+(\d+))")).match(arguments); + + appendSpecifer = match.hasMatch(); // assume non-modern if no standard is specified + if (appendSpecifer) { + const int standard = match.captured(1).toInt(); + appendSpecifer = (standard != 98 && standard != 03); + } + } + + if (appendSpecifer) { + replacement.append(QLatin1String(" override;")); + } else { + replacement.append(QLatin1Char(';')); + } + + view->document()->replaceText(word, replacement); } private: diff --git a/plugins/clang/tests/test_codecompletion.h b/plugins/clang/tests/test_codecompletion.h --- a/plugins/clang/tests/test_codecompletion.h +++ b/plugins/clang/tests/test_codecompletion.h @@ -37,6 +37,8 @@ void testClangCodeCompletion_data(); void testVirtualOverride(); void testVirtualOverride_data(); + void testOverrideExecute(); + void testOverrideExecute_data(); void testImplement(); void testImplement_data(); void testImplementOtherFile(); diff --git a/plugins/clang/tests/test_codecompletion.cpp b/plugins/clang/tests/test_codecompletion.cpp --- a/plugins/clang/tests/test_codecompletion.cpp +++ b/plugins/clang/tests/test_codecompletion.cpp @@ -613,6 +613,71 @@ )" << CompletionItems{{8, 14}, {}}; } +void TestCodeCompletion::testOverrideExecute() +{ + QFETCH(QString, code); + QFETCH(CompletionItems, expectedItems); + QFETCH(QString, itemToExecute); + QFETCH(QString, cppStandard); + QFETCH(QString, expectedCode); + + QTemporaryDir directory; + TestProject testProject {Path{directory.path()}}; + auto t = testProject.path().toLocalFile(); + auto configGroup = testProject.projectConfiguration()->group("CustomDefinesAndIncludes").group("ProjectPath0"); + configGroup.writeEntry("Path", "."); + configGroup.writeEntry("parserArguments", cppStandard); + configGroup.sync(); + m_projectController->addProject(&testProject); + + TestFile file(code, QStringLiteral("cpp"), &testProject, directory.path()); + QVERIFY(file.parseAndWait(TopDUContext::AllDeclarationsContextsUsesAndAST)); + + auto executeItem = [=] (const ClangCodeCompletionItemTester& tester) { + auto item = tester.findItem(itemToExecute); + QVERIFY(item); + auto view = createView(tester.completionContext->duContext()->url().toUrl(), this); + item->execute(view.get(), view->document()->wordRangeAt(expectedItems.position)); + QCOMPARE(view->document()->text(), expectedCode); + }; + executeCompletionTest(file.topContext(), expectedItems, NoMacroOrBuiltin, executeItem); + m_projectController->closeProject(&testProject); +} + +void TestCodeCompletion::testOverrideExecute_data() +{ + QTest::addColumn("code"); + QTest::addColumn("expectedItems"); + QTest::addColumn("itemToExecute"); + QTest::addColumn("cppStandard"); + QTest::addColumn("expectedCode"); + + QTest::newRow("override-modern") + << "class Foo { virtual int bar(char c); };\nclass Baz : Foo\n{\n};" + << CompletionItems{{3, 0}, {"Baz", "Foo", "bar(char c)"}} + << "bar(char c)" + << "-std=c++11" + << "class Foo { virtual int bar(char c); };\n" + "class Baz : Foo\n{\nint bar(char c) override;};"; + + QTest::newRow("override-non-modern") + << "class Foo { virtual int bar(char c); };\nclass Baz : Foo\n{\n};" + << CompletionItems{{3, 0}, {"Baz", "Foo", "bar(char c)"}} + << "bar(char c)" + << "-std=c++98" + << "class Foo { virtual int bar(char c); };\n" + "class Baz : Foo\n{\nint bar(char c);};"; + + QTest::newRow("override-default") + << "class Foo { virtual int bar(char c); };\nclass Baz : Foo\n{\n};" + << CompletionItems{{3, 0}, {"Baz", "Foo", "bar(char c)"}} + << "bar(char c)" + << "" + << "class Foo { virtual int bar(char c); };\n" + "class Baz : Foo\n{\nint bar(char c) override;};"; +} + + void TestCodeCompletion::testImplement() { QFETCH(QString, code); @@ -1411,6 +1476,7 @@ << CompletionItems({1, 7}, {"** Foo::bar(int x)"}) << "** Foo::bar(int x)" << "class Foo { int** bar(int x); };\nint ** Foo::bar(int x)\n{\n}\n"; + } void TestCodeCompletion::testIgnoreGccBuiltins()