From 63c6ba1ba356599eeaf64c9f3b80b13294f0873d Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 17 May 2024 14:15:44 +0200 Subject: [PATCH] CppEditor: Add quickfix for ordering member function implementations ... according to the declaration order. Fixes: QTCREATORBUG-6199 Change-Id: I37bbffeb53e0f16589ffff2f54232e21b300382c Reviewed-by: David Schulz --- src/plugins/cppeditor/CMakeLists.txt | 1 + src/plugins/cppeditor/cppeditor.qbs | 2 + src/plugins/cppeditor/cppeditor.qrc | 16 + .../cppeditor/quickfixes/cppquickfix.cpp | 2 + .../synchronizememberfunctionorder.cpp | 358 ++++++++++++++++++ .../synchronizememberfunctionorder.h | 8 + .../already-sorted/already-sorted.pro | 1 + .../already-sorted/header.h | 9 + .../already-sorted/header.h_expected | 9 + .../different-locations.pro | 2 + .../different-locations/header.h | 15 + .../different-locations/header.h_expected | 15 + .../different-locations/impl1.cpp | 5 + .../different-locations/impl1.cpp_expected | 5 + .../different-locations/impl2.cpp | 6 + .../different-locations/impl2.cpp_expected | 6 + .../no-out-of-line/header.h | 5 + .../no-out-of-line/header.h_expected | 5 + .../no-out-of-line/no-out-of-line.pro | 1 + .../reorder-member-impls/templates/header.h | 10 + .../templates/header.h_expected | 10 + .../templates/templates.pro | 1 + 22 files changed, 492 insertions(+) create mode 100644 src/plugins/cppeditor/quickfixes/synchronizememberfunctionorder.cpp create mode 100644 src/plugins/cppeditor/quickfixes/synchronizememberfunctionorder.h create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/already-sorted/already-sorted.pro create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/already-sorted/header.h create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/already-sorted/header.h_expected create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/different-locations.pro create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/header.h create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/header.h_expected create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl1.cpp create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl1.cpp_expected create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl2.cpp create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl2.cpp_expected create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/no-out-of-line/header.h create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/no-out-of-line/header.h_expected create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/no-out-of-line/no-out-of-line.pro create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/templates/header.h create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/templates/header.h_expected create mode 100644 src/plugins/cppeditor/testcases/reorder-member-impls/templates/templates.pro diff --git a/src/plugins/cppeditor/CMakeLists.txt b/src/plugins/cppeditor/CMakeLists.txt index 90685aaf348..aef17fe4e31 100644 --- a/src/plugins/cppeditor/CMakeLists.txt +++ b/src/plugins/cppeditor/CMakeLists.txt @@ -127,6 +127,7 @@ add_qtc_plugin(CppEditor quickfixes/rewritecomment.cpp quickfixes/rewritecomment.cpp quickfixes/rewritecontrolstatements.cpp quickfixes/rewritecontrolstatements.h quickfixes/splitsimpledeclaration.cpp quickfixes/splitsimpledeclaration.h + quickfixes/synchronizememberfunctionorder.cpp quickfixes/synchronizememberfunctionorder.h resourcepreviewhoverhandler.cpp resourcepreviewhoverhandler.h searchsymbols.cpp searchsymbols.h semantichighlighter.cpp semantichighlighter.h diff --git a/src/plugins/cppeditor/cppeditor.qbs b/src/plugins/cppeditor/cppeditor.qbs index 24beed5dd18..c563c760971 100644 --- a/src/plugins/cppeditor/cppeditor.qbs +++ b/src/plugins/cppeditor/cppeditor.qbs @@ -283,6 +283,8 @@ QtcPlugin { "rewritecontrolstatements.h", "splitsimpledeclaration.cpp", "splitsimpledeclaration.h", + "synchronizememberfunctionorder.cpp", + "synchronizememberfunctionorder.h", ] } diff --git a/src/plugins/cppeditor/cppeditor.qrc b/src/plugins/cppeditor/cppeditor.qrc index e90b587dc2d..3a5ace117d3 100644 --- a/src/plugins/cppeditor/cppeditor.qrc +++ b/src/plugins/cppeditor/cppeditor.qrc @@ -41,5 +41,21 @@ testcases/move-class/template/theheader.h testcases/move-class/template/theheader.h_expected testcases/move-class/complex/theclass.h_expected + testcases/reorder-member-impls/different-locations/different-locations.pro + testcases/reorder-member-impls/different-locations/header.h + testcases/reorder-member-impls/different-locations/header.h_expected + testcases/reorder-member-impls/different-locations/impl1.cpp + testcases/reorder-member-impls/different-locations/impl1.cpp_expected + testcases/reorder-member-impls/different-locations/impl2.cpp + testcases/reorder-member-impls/different-locations/impl2.cpp_expected + testcases/reorder-member-impls/already-sorted/already-sorted.pro + testcases/reorder-member-impls/already-sorted/header.h + testcases/reorder-member-impls/no-out-of-line/header.h + testcases/reorder-member-impls/no-out-of-line/no-out-of-line.pro + testcases/reorder-member-impls/already-sorted/header.h_expected + testcases/reorder-member-impls/no-out-of-line/header.h_expected + testcases/reorder-member-impls/templates/header.h + testcases/reorder-member-impls/templates/header.h_expected + testcases/reorder-member-impls/templates/templates.pro diff --git a/src/plugins/cppeditor/quickfixes/cppquickfix.cpp b/src/plugins/cppeditor/quickfixes/cppquickfix.cpp index 006008dd88c..a4052db83ec 100644 --- a/src/plugins/cppeditor/quickfixes/cppquickfix.cpp +++ b/src/plugins/cppeditor/quickfixes/cppquickfix.cpp @@ -33,6 +33,7 @@ #include "rewritecomment.h" #include "rewritecontrolstatements.h" #include "splitsimpledeclaration.h" +#include "synchronizememberfunctionorder.h" #include #include @@ -135,6 +136,7 @@ void createCppQuickFixFactories() registerRewriteCommentQuickfixes(); registerRewriteControlStatementQuickfixes(); registerSplitSimpleDeclarationQuickfix(); + registerSynchronizeMemberFunctionOrderQuickfix(); } static QList g_cppQuickFixFactories; diff --git a/src/plugins/cppeditor/quickfixes/synchronizememberfunctionorder.cpp b/src/plugins/cppeditor/quickfixes/synchronizememberfunctionorder.cpp new file mode 100644 index 00000000000..400988bb659 --- /dev/null +++ b/src/plugins/cppeditor/quickfixes/synchronizememberfunctionorder.cpp @@ -0,0 +1,358 @@ +// 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 "synchronizememberfunctionorder.h" + +#include "../cppeditortr.h" +#include "../cppeditorwidget.h" +#include "../cpprefactoringchanges.h" +#include "cppquickfix.h" +#include "cppquickfixhelpers.h" + +#include +#include + +#include +#include + +#ifdef WITH_TESTS +#include "cppquickfix_test.h" +#include +#include +#include +#endif + +#include + +using namespace Core; +using namespace CPlusPlus; +using namespace Utils; + +namespace CppEditor::Internal { +namespace { + +class SynchronizeMemberFunctionOrderOp : public CppQuickFixOperation +{ +public: + SynchronizeMemberFunctionOrderOp( + const CppQuickFixInterface &interface, const QList &decls) + : CppQuickFixOperation(interface), m_state(std::make_shared()) + { + setDescription( + Tr::tr("Re-order Member Function Definitions According to Declaration Order")); + m_state->decls = decls; + } + +private: + struct DefLocation { + Symbol *decl = nullptr; + Link defLoc; + bool operator==(const DefLocation &other) const + { + return decl == other.decl && defLoc == other.defLoc; + } + }; + using DefLocations = QList; + struct State { + using Ptr = std::shared_ptr; + + void insertSorted(Symbol *decl, const Link &link) { + DefLocations &dl = defLocations[link.targetFilePath]; + DefLocation newElem{decl, link}; + const auto cmp = [](const DefLocation &elem, const DefLocation &value) { + if (elem.defLoc.targetLine < value.defLoc.targetLine) + return true; + if (elem.defLoc.targetLine > value.defLoc.targetLine) + return false; + return elem.defLoc.targetColumn < value.defLoc.targetColumn; + }; + dl.insert(std::lower_bound(dl.begin(), dl.end(), newElem, cmp), newElem); + } + + QList decls; + QHash defLocations; + int remainingFollowSymbolOps = 0; + }; + + void perform() override + { + for (Symbol * const decl : std::as_const(m_state->decls)) { + QTextCursor cursor(currentFile()->document()->begin()); + TranslationUnit * const tu = currentFile()->cppDocument()->translationUnit(); + const int declPos = tu->getTokenPositionInDocument(decl->sourceLocation(), + currentFile()->document()); + cursor.setPosition(declPos); + const CursorInEditor cursorInEditor( + cursor, + decl->filePath(), + qobject_cast(currentFile()->editor()), + currentFile()->editor()->textDocument(), + currentFile()->cppDocument()); + + const auto callback = [decl, declPos, doc = cursor.document(), state = m_state]( + const Link &link) { + class FinishedChecker + { + public: + FinishedChecker(const State::Ptr &state) : m_state(state) + {} + ~FinishedChecker() + { + if (--m_state->remainingFollowSymbolOps == 0) + finish(m_state); + }; + private: + const State::Ptr &m_state; + } finishedChecker(state); + + if (!link.hasValidTarget()) + return; + if (decl->filePath() == link.targetFilePath) { + const int linkPos = Text::positionInText(doc, link.targetLine, + link.targetColumn + 1); + if (linkPos == declPos) + return; + } + state->insertSorted(decl, link); + }; + + ++m_state->remainingFollowSymbolOps; + + // Force queued execution, as the built-in editor can run the callback synchronously. + const auto followSymbol = [cursorInEditor, callback] { + CppModelManager::followSymbol( + cursorInEditor, callback, true, false, FollowSymbolMode::Exact); + }; + QMetaObject::invokeMethod(CppModelManager::instance(), followSymbol, Qt::QueuedConnection); + } + } + + // TODO: Move to some central place for re-use + static CppEditorWidget *getEditorWidget(const FilePath &filePath) + { + CppEditorWidget *editorWidget = nullptr; + const QList editors = DocumentModel::editorsForFilePath(filePath); + for (IEditor *editor : editors) { + const auto textEditor = qobject_cast(editor); + if (textEditor) + editorWidget = qobject_cast(textEditor->editorWidget()); + if (editorWidget) + return editorWidget; + } + return nullptr; + } + + static void finish(const State::Ptr &state) + { + CppRefactoringChanges factory{CppModelManager::snapshot()}; + + // TODO: Move to some central place for re-use. + const auto createRefactoringFile = [&factory](const FilePath &filePath) + { + CppEditorWidget * const editorWidget = getEditorWidget(filePath); + return editorWidget ? factory.file(editorWidget, editorWidget->semanticInfo().doc) + : factory.cppFile(filePath); + }; + + const auto findAstRange = [](const CppRefactoringFile &file, const Link &pos) { + const QList astPath = ASTPath( + file.cppDocument())(pos.targetLine, pos.targetColumn + 1); + for (auto it = astPath.rbegin(); it != astPath.rend(); ++it) { + if (const auto funcDef = (*it)->asFunctionDefinition()) { + AST *ast = funcDef; + for (auto next = std::next(it); + next != astPath.rend() && (*next)->asTemplateDeclaration(); + ++next) { + ast = *next; + } + return file.range(ast); + } + } + return ChangeSet::Range(); + }; + + for (auto it = state->defLocations.cbegin(); it != state->defLocations.cend(); ++it) { + const DefLocations &defLocsActualOrder = it.value(); + const DefLocations defLocsExpectedOrder = Utils::sorted( + defLocsActualOrder, [](const DefLocation &loc1, const DefLocation &loc2) { + return loc1.decl->sourceLocation() < loc2.decl->sourceLocation(); + }); + if (defLocsExpectedOrder == defLocsActualOrder) + continue; + + CppRefactoringFilePtr file = createRefactoringFile(it.key()); + ChangeSet changes; + for (int i = 0; i < defLocsActualOrder.size(); ++i) { + const DefLocation &actualLoc = defLocsActualOrder[i]; + int expectedPos = -1; + for (int j = 0; j < defLocsExpectedOrder.size(); ++j) { + if (defLocsExpectedOrder[j].decl == actualLoc.decl) { + expectedPos = j; + break; + } + } + if (expectedPos == i) + continue; + const ChangeSet::Range actualRange = findAstRange(*file, actualLoc.defLoc); + const ChangeSet::Range expectedRange + = findAstRange(*file, defLocsActualOrder[expectedPos].defLoc); + if (actualRange.end > actualRange.start && expectedRange.end > expectedRange.start) + changes.move(actualRange, expectedRange.start); + } + QTC_ASSERT(!changes.hadErrors(), continue); + file->setChangeSet(changes); + file->apply(); + } + } + + const State::Ptr m_state; +}; + +//! Ensures relative order of member function implementations is the same as declaration order. +class SynchronizeMemberFunctionOrder : public CppQuickFixFactory +{ +#ifdef WITH_TESTS +public: + static QObject *createTest(); +#endif + +private: + void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override + { + ClassSpecifierAST * const classAst = astForClassOperations(interface); + if (!classAst || !classAst->symbol) + return; + + QList memberFunctions; + const TranslationUnit * const tu + = interface.currentFile()->cppDocument()->translationUnit(); + for (int i = 0; i < classAst->symbol->memberCount(); ++i) { + Symbol *member = classAst->symbol->memberAt(i); + + // Skip macros + if (tu->tokenAt(member->sourceLocation()).expanded()) + continue; + + if (const auto templ = member->asTemplate()) + member = templ->declaration(); + if (member->type()->asFunctionType() && !member->asFunction()) + memberFunctions << member; + } + if (!memberFunctions.isEmpty()) + result << new SynchronizeMemberFunctionOrderOp(interface, memberFunctions); + } +}; + +#ifdef WITH_TESTS +using namespace Tests; + +class SynchronizeMemberFunctionOrderTest : public QObject +{ + Q_OBJECT + +private slots: + void test_data() + { + QTest::addColumn("projectName"); + QTest::addColumn("expectChanges"); + + QTest::newRow("no out-of-line definitions") << "no-out-of-line" << false; + QTest::newRow("already sorted") << "already-sorted" << false; + QTest::newRow("different impl locations") << "different-locations" << true; + QTest::newRow("templates") << "templates" << true; + } + + void test() + { + QFETCH(QString, projectName); + QFETCH(bool, expectChanges); + using namespace CppEditor::Tests; + using namespace ProjectExplorer; + using namespace TextEditor; + + // Set up project. + Kit * const kit = Utils::findOr(KitManager::kits(), nullptr, [](const Kit *k) { + return k->isValid() && !k->hasWarning() && k->value("QtSupport.QtInformation").isValid(); + }); + if (!kit) + QSKIP("The test requires at least one valid kit with a valid Qt"); + const auto projectDir = std::make_unique( + ":/cppeditor/testcases/reorder-member-impls/" + projectName); + SourceFilesRefreshGuard refreshGuard; + ProjectOpenerAndCloser projectMgr; + QVERIFY(projectMgr.open(projectDir->absolutePath(projectName + ".pro"), true, kit)); + QVERIFY(refreshGuard.wait()); + + // Open header file and locate class. + const auto headerFilePath = projectDir->absolutePath("header.h"); + QVERIFY2(headerFilePath.exists(), qPrintable(headerFilePath.toUserOutput())); + const auto editor = qobject_cast(EditorManager::openEditor(headerFilePath)); + QVERIFY(editor); + const auto doc = qobject_cast(editor->document()); + QVERIFY(doc); + QTextCursor classCursor = doc->document()->find("struct S"); + QVERIFY(!classCursor.isNull()); + editor->setCursorPosition(classCursor.position()); + const auto editorWidget = qobject_cast(editor->editorWidget()); + QVERIFY(editorWidget); + QVERIFY(TestCase::waitForRehighlightedSemanticDocument(editorWidget)); + + // Query factory. + SynchronizeMemberFunctionOrder factory; + CppQuickFixInterface quickFixInterface(editorWidget, ExplicitlyInvoked); + QuickFixOperations operations; + factory.match(quickFixInterface, operations); + operations.first()->perform(); + if (expectChanges) + QVERIFY(waitForSignalOrTimeout(doc, &IDocument::saved, 30000)); + QTest::qWait(1000); + + // Compare all files. + const FileFilter filter({"*_expected"}, QDir::Files); + const FilePaths expectedDocuments = projectDir->filePath().dirEntries(filter); + QVERIFY(!expectedDocuments.isEmpty()); + for (const FilePath &expected : expectedDocuments) { + static const QString suffix = "_expected"; + const FilePath actual = expected.parentDir() + .pathAppended(expected.fileName().chopped(suffix.length())); + QVERIFY(actual.exists()); + const auto actualContents = actual.fileContents(); + QVERIFY(actualContents); + const auto expectedContents = expected.fileContents(); + const QByteArrayList actualLines = actualContents->split('\n'); + const QByteArrayList expectedLines = expectedContents->split('\n'); + if (actualLines.size() != expectedLines.size()) { + qDebug().noquote().nospace() << "---\n" << *expectedContents << "EOF"; + qDebug().noquote().nospace() << "+++\n" << *actualContents << "EOF"; + } + QCOMPARE(actualLines.size(), expectedLines.size()); + for (int i = 0; i < actualLines.size(); ++i) { + const QByteArray actualLine = actualLines.at(i); + const QByteArray expectedLine = expectedLines.at(i); + if (actualLine != expectedLine) + qDebug() << "Unexpected content in line" << (i + 1) << "of file" + << actual.fileName(); + QCOMPARE(actualLine, expectedLine); + } + } + } +}; + +QObject *SynchronizeMemberFunctionOrder::createTest() +{ + return new SynchronizeMemberFunctionOrderTest; +} + +#endif +} // namespace + +void registerSynchronizeMemberFunctionOrderQuickfix() +{ + CppQuickFixFactory::registerFactory(); +} + +} // namespace CppEditor::Internal + +#ifdef WITH_TESTS +#include +#endif diff --git a/src/plugins/cppeditor/quickfixes/synchronizememberfunctionorder.h b/src/plugins/cppeditor/quickfixes/synchronizememberfunctionorder.h new file mode 100644 index 00000000000..da6ad971dbb --- /dev/null +++ b/src/plugins/cppeditor/quickfixes/synchronizememberfunctionorder.h @@ -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 registerSynchronizeMemberFunctionOrderQuickfix(); +} // namespace CppEditor::Internal diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/already-sorted/already-sorted.pro b/src/plugins/cppeditor/testcases/reorder-member-impls/already-sorted/already-sorted.pro new file mode 100644 index 00000000000..70518012691 --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/already-sorted/already-sorted.pro @@ -0,0 +1 @@ +HEADERS = header.h diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/already-sorted/header.h b/src/plugins/cppeditor/testcases/reorder-member-impls/already-sorted/header.h new file mode 100644 index 00000000000..c0d7e0caa77 --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/already-sorted/header.h @@ -0,0 +1,9 @@ +struct S { + void firstFunction(); + void secondFunction(); + void thirdFunction(); +}; + +void S::firstFunction() {} +void S::secondFunction() {} +void S::thirdFunction() {} diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/already-sorted/header.h_expected b/src/plugins/cppeditor/testcases/reorder-member-impls/already-sorted/header.h_expected new file mode 100644 index 00000000000..c0d7e0caa77 --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/already-sorted/header.h_expected @@ -0,0 +1,9 @@ +struct S { + void firstFunction(); + void secondFunction(); + void thirdFunction(); +}; + +void S::firstFunction() {} +void S::secondFunction() {} +void S::thirdFunction() {} diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/different-locations.pro b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/different-locations.pro new file mode 100644 index 00000000000..a8dd832020e --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/different-locations.pro @@ -0,0 +1,2 @@ +SOURCES = impl1.cpp impl2.cpp +HEADERS = header.h diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/header.h b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/header.h new file mode 100644 index 00000000000..15a428eb7cb --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/header.h @@ -0,0 +1,15 @@ +struct S { + void firstFunction(); + void secondFunction(); + void thirdFunction() {} + void fourthFunction(); + void fifthFunction(); + void sixthFunction(); + void seventhFunction(); + void eighthFunction(); + void ninthFunction(); + void tenthFunction(); +}; + +void S::tenthFunction() {} +void S::fourthFunction() {} diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/header.h_expected b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/header.h_expected new file mode 100644 index 00000000000..eeec93f300a --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/header.h_expected @@ -0,0 +1,15 @@ +struct S { + void firstFunction(); + void secondFunction(); + void thirdFunction() {} + void fourthFunction(); + void fifthFunction(); + void sixthFunction(); + void seventhFunction(); + void eighthFunction(); + void ninthFunction(); + void tenthFunction(); +}; + +void S::fourthFunction() {} +void S::tenthFunction() {} diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl1.cpp b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl1.cpp new file mode 100644 index 00000000000..816fef17796 --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl1.cpp @@ -0,0 +1,5 @@ +#include "header.h" + +void S::ninthFunction() {} +void S::firstFunction() {} +void S::secondFunction() {} diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl1.cpp_expected b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl1.cpp_expected new file mode 100644 index 00000000000..24d0f3a212b --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl1.cpp_expected @@ -0,0 +1,5 @@ +#include "header.h" + +void S::firstFunction() {} +void S::secondFunction() {} +void S::ninthFunction() {} diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl2.cpp b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl2.cpp new file mode 100644 index 00000000000..f1040e089ec --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl2.cpp @@ -0,0 +1,6 @@ +#include "header.h" + +void S::eighthFunction() {} +void S::seventhFunction() {} +void S::sixthFunction() {} +void S::fifthFunction() {} diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl2.cpp_expected b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl2.cpp_expected new file mode 100644 index 00000000000..2b65df96a5a --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/different-locations/impl2.cpp_expected @@ -0,0 +1,6 @@ +#include "header.h" + +void S::fifthFunction() {} +void S::sixthFunction() {} +void S::seventhFunction() {} +void S::eighthFunction() {} diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/no-out-of-line/header.h b/src/plugins/cppeditor/testcases/reorder-member-impls/no-out-of-line/header.h new file mode 100644 index 00000000000..cff89451279 --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/no-out-of-line/header.h @@ -0,0 +1,5 @@ +struct S { + void firstFunction() {} + void secondFunction(); + void thirdFunction() {} +}; diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/no-out-of-line/header.h_expected b/src/plugins/cppeditor/testcases/reorder-member-impls/no-out-of-line/header.h_expected new file mode 100644 index 00000000000..cff89451279 --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/no-out-of-line/header.h_expected @@ -0,0 +1,5 @@ +struct S { + void firstFunction() {} + void secondFunction(); + void thirdFunction() {} +}; diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/no-out-of-line/no-out-of-line.pro b/src/plugins/cppeditor/testcases/reorder-member-impls/no-out-of-line/no-out-of-line.pro new file mode 100644 index 00000000000..70518012691 --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/no-out-of-line/no-out-of-line.pro @@ -0,0 +1 @@ +HEADERS = header.h diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/templates/header.h b/src/plugins/cppeditor/testcases/reorder-member-impls/templates/header.h new file mode 100644 index 00000000000..08b33a51d98 --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/templates/header.h @@ -0,0 +1,10 @@ +template struct S { + void firstFunction(); + template void secondFunction(U); + template void irrelevantFunction(U) {} + void thirdFunction(); +}; + +template template void S::secondFunction(U) {} +template void S::thirdFunction() {} +template void S::firstFunction() {} diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/templates/header.h_expected b/src/plugins/cppeditor/testcases/reorder-member-impls/templates/header.h_expected new file mode 100644 index 00000000000..f182bbe62d4 --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/templates/header.h_expected @@ -0,0 +1,10 @@ +template struct S { + void firstFunction(); + template void secondFunction(U); + template void irrelevantFunction(U) {} + void thirdFunction(); +}; + +template void S::firstFunction() {} +template template void S::secondFunction(U) {} +template void S::thirdFunction() {} diff --git a/src/plugins/cppeditor/testcases/reorder-member-impls/templates/templates.pro b/src/plugins/cppeditor/testcases/reorder-member-impls/templates/templates.pro new file mode 100644 index 00000000000..70518012691 --- /dev/null +++ b/src/plugins/cppeditor/testcases/reorder-member-impls/templates/templates.pro @@ -0,0 +1 @@ +HEADERS = header.h