forked from qt-creator/qt-creator
CppEditor: Add quickfix for ordering member function implementations
... according to the declaration order. Fixes: QTCREATORBUG-6199 Change-Id: I37bbffeb53e0f16589ffff2f54232e21b300382c Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -127,6 +127,7 @@ add_qtc_plugin(CppEditor
|
|||||||
quickfixes/rewritecomment.cpp quickfixes/rewritecomment.cpp
|
quickfixes/rewritecomment.cpp quickfixes/rewritecomment.cpp
|
||||||
quickfixes/rewritecontrolstatements.cpp quickfixes/rewritecontrolstatements.h
|
quickfixes/rewritecontrolstatements.cpp quickfixes/rewritecontrolstatements.h
|
||||||
quickfixes/splitsimpledeclaration.cpp quickfixes/splitsimpledeclaration.h
|
quickfixes/splitsimpledeclaration.cpp quickfixes/splitsimpledeclaration.h
|
||||||
|
quickfixes/synchronizememberfunctionorder.cpp quickfixes/synchronizememberfunctionorder.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
|
||||||
|
|||||||
@@ -283,6 +283,8 @@ QtcPlugin {
|
|||||||
"rewritecontrolstatements.h",
|
"rewritecontrolstatements.h",
|
||||||
"splitsimpledeclaration.cpp",
|
"splitsimpledeclaration.cpp",
|
||||||
"splitsimpledeclaration.h",
|
"splitsimpledeclaration.h",
|
||||||
|
"synchronizememberfunctionorder.cpp",
|
||||||
|
"synchronizememberfunctionorder.h",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,5 +41,21 @@
|
|||||||
<file>testcases/move-class/template/theheader.h</file>
|
<file>testcases/move-class/template/theheader.h</file>
|
||||||
<file>testcases/move-class/template/theheader.h_expected</file>
|
<file>testcases/move-class/template/theheader.h_expected</file>
|
||||||
<file>testcases/move-class/complex/theclass.h_expected</file>
|
<file>testcases/move-class/complex/theclass.h_expected</file>
|
||||||
|
<file>testcases/reorder-member-impls/different-locations/different-locations.pro</file>
|
||||||
|
<file>testcases/reorder-member-impls/different-locations/header.h</file>
|
||||||
|
<file>testcases/reorder-member-impls/different-locations/header.h_expected</file>
|
||||||
|
<file>testcases/reorder-member-impls/different-locations/impl1.cpp</file>
|
||||||
|
<file>testcases/reorder-member-impls/different-locations/impl1.cpp_expected</file>
|
||||||
|
<file>testcases/reorder-member-impls/different-locations/impl2.cpp</file>
|
||||||
|
<file>testcases/reorder-member-impls/different-locations/impl2.cpp_expected</file>
|
||||||
|
<file>testcases/reorder-member-impls/already-sorted/already-sorted.pro</file>
|
||||||
|
<file>testcases/reorder-member-impls/already-sorted/header.h</file>
|
||||||
|
<file>testcases/reorder-member-impls/no-out-of-line/header.h</file>
|
||||||
|
<file>testcases/reorder-member-impls/no-out-of-line/no-out-of-line.pro</file>
|
||||||
|
<file>testcases/reorder-member-impls/already-sorted/header.h_expected</file>
|
||||||
|
<file>testcases/reorder-member-impls/no-out-of-line/header.h_expected</file>
|
||||||
|
<file>testcases/reorder-member-impls/templates/header.h</file>
|
||||||
|
<file>testcases/reorder-member-impls/templates/header.h_expected</file>
|
||||||
|
<file>testcases/reorder-member-impls/templates/templates.pro</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "rewritecomment.h"
|
#include "rewritecomment.h"
|
||||||
#include "rewritecontrolstatements.h"
|
#include "rewritecontrolstatements.h"
|
||||||
#include "splitsimpledeclaration.h"
|
#include "splitsimpledeclaration.h"
|
||||||
|
#include "synchronizememberfunctionorder.h"
|
||||||
|
|
||||||
#include <extensionsystem/pluginmanager.h>
|
#include <extensionsystem/pluginmanager.h>
|
||||||
#include <extensionsystem/pluginspec.h>
|
#include <extensionsystem/pluginspec.h>
|
||||||
@@ -135,6 +136,7 @@ void createCppQuickFixFactories()
|
|||||||
registerRewriteCommentQuickfixes();
|
registerRewriteCommentQuickfixes();
|
||||||
registerRewriteControlStatementQuickfixes();
|
registerRewriteControlStatementQuickfixes();
|
||||||
registerSplitSimpleDeclarationQuickfix();
|
registerSplitSimpleDeclarationQuickfix();
|
||||||
|
registerSynchronizeMemberFunctionOrderQuickfix();
|
||||||
}
|
}
|
||||||
|
|
||||||
static QList<CppQuickFixFactory *> g_cppQuickFixFactories;
|
static QList<CppQuickFixFactory *> g_cppQuickFixFactories;
|
||||||
|
|||||||
@@ -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 <coreplugin/editormanager/editormanager.h>
|
||||||
|
#include <cplusplus/ASTPath.h>
|
||||||
|
|
||||||
|
#include <QList>
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
#ifdef WITH_TESTS
|
||||||
|
#include "cppquickfix_test.h"
|
||||||
|
#include <projectexplorer/kitmanager.h>
|
||||||
|
#include <texteditor/textdocument.h>
|
||||||
|
#include <QtTest>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
using namespace Core;
|
||||||
|
using namespace CPlusPlus;
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
|
namespace CppEditor::Internal {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class SynchronizeMemberFunctionOrderOp : public CppQuickFixOperation
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SynchronizeMemberFunctionOrderOp(
|
||||||
|
const CppQuickFixInterface &interface, const QList<Symbol *> &decls)
|
||||||
|
: CppQuickFixOperation(interface), m_state(std::make_shared<State>())
|
||||||
|
{
|
||||||
|
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<DefLocation>;
|
||||||
|
struct State {
|
||||||
|
using Ptr = std::shared_ptr<State>;
|
||||||
|
|
||||||
|
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<Symbol *> decls;
|
||||||
|
QHash<FilePath, DefLocations> 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<CppEditorWidget *>(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<IEditor *> editors = DocumentModel::editorsForFilePath(filePath);
|
||||||
|
for (IEditor *editor : editors) {
|
||||||
|
const auto textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor);
|
||||||
|
if (textEditor)
|
||||||
|
editorWidget = qobject_cast<CppEditorWidget *>(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<AST *> 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<Symbol *> 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<QString>("projectName");
|
||||||
|
QTest::addColumn<bool>("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<TemporaryCopiedDir>(
|
||||||
|
":/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<BaseTextEditor *>(EditorManager::openEditor(headerFilePath));
|
||||||
|
QVERIFY(editor);
|
||||||
|
const auto doc = qobject_cast<TextEditor::TextDocument *>(editor->document());
|
||||||
|
QVERIFY(doc);
|
||||||
|
QTextCursor classCursor = doc->document()->find("struct S");
|
||||||
|
QVERIFY(!classCursor.isNull());
|
||||||
|
editor->setCursorPosition(classCursor.position());
|
||||||
|
const auto editorWidget = qobject_cast<CppEditorWidget *>(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<SynchronizeMemberFunctionOrder>();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace CppEditor::Internal
|
||||||
|
|
||||||
|
#ifdef WITH_TESTS
|
||||||
|
#include <synchronizememberfunctionorder.moc>
|
||||||
|
#endif
|
||||||
@@ -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
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
HEADERS = header.h
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
struct S {
|
||||||
|
void firstFunction();
|
||||||
|
void secondFunction();
|
||||||
|
void thirdFunction();
|
||||||
|
};
|
||||||
|
|
||||||
|
void S::firstFunction() {}
|
||||||
|
void S::secondFunction() {}
|
||||||
|
void S::thirdFunction() {}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
struct S {
|
||||||
|
void firstFunction();
|
||||||
|
void secondFunction();
|
||||||
|
void thirdFunction();
|
||||||
|
};
|
||||||
|
|
||||||
|
void S::firstFunction() {}
|
||||||
|
void S::secondFunction() {}
|
||||||
|
void S::thirdFunction() {}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
SOURCES = impl1.cpp impl2.cpp
|
||||||
|
HEADERS = 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() {}
|
||||||
@@ -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() {}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
void S::ninthFunction() {}
|
||||||
|
void S::firstFunction() {}
|
||||||
|
void S::secondFunction() {}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
void S::firstFunction() {}
|
||||||
|
void S::secondFunction() {}
|
||||||
|
void S::ninthFunction() {}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
void S::eighthFunction() {}
|
||||||
|
void S::seventhFunction() {}
|
||||||
|
void S::sixthFunction() {}
|
||||||
|
void S::fifthFunction() {}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include "header.h"
|
||||||
|
|
||||||
|
void S::fifthFunction() {}
|
||||||
|
void S::sixthFunction() {}
|
||||||
|
void S::seventhFunction() {}
|
||||||
|
void S::eighthFunction() {}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
struct S {
|
||||||
|
void firstFunction() {}
|
||||||
|
void secondFunction();
|
||||||
|
void thirdFunction() {}
|
||||||
|
};
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
struct S {
|
||||||
|
void firstFunction() {}
|
||||||
|
void secondFunction();
|
||||||
|
void thirdFunction() {}
|
||||||
|
};
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
HEADERS = header.h
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
template <typename T> struct S {
|
||||||
|
void firstFunction();
|
||||||
|
template<typename U> void secondFunction(U);
|
||||||
|
template<typename U> void irrelevantFunction(U) {}
|
||||||
|
void thirdFunction();
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> template<typename U> void S<T>::secondFunction(U) {}
|
||||||
|
template<typename T> void S<T>::thirdFunction() {}
|
||||||
|
template<typename T> void S<T>::firstFunction() {}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
template <typename T> struct S {
|
||||||
|
void firstFunction();
|
||||||
|
template<typename U> void secondFunction(U);
|
||||||
|
template<typename U> void irrelevantFunction(U) {}
|
||||||
|
void thirdFunction();
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T> void S<T>::firstFunction() {}
|
||||||
|
template<typename T> template<typename U> void S<T>::secondFunction(U) {}
|
||||||
|
template<typename T> void S<T>::thirdFunction() {}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
HEADERS = header.h
|
||||||
Reference in New Issue
Block a user