summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2020-07-22 17:19:28 +0200
committerChristian Kandeler <christian.kandeler@qt.io>2020-07-29 11:56:07 +0000
commit77d13f08ba9e465725d1ca3a677aae949732804b (patch)
treeebc15427128e5f8950503852e6fb95eb252f647b
parent120540f1db4e71d86da3e110dede742ae97b131d (diff)
downloadqt-creator-77d13f08ba9e465725d1ca3a677aae949732804b.tar.gz
CppEditor: Let users create implementations for all member functions
... in one go. Fixes: QTCREATORBUG-12164 Change-Id: Ifc81c8b1caf4319ce57882375f513d72e4c0ea52 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
-rw-r--r--src/plugins/cppeditor/cppeditorplugin.h2
-rw-r--r--src/plugins/cppeditor/cppquickfix_test.cpp131
-rw-r--r--src/plugins/cppeditor/cppquickfixes.cpp385
-rw-r--r--src/plugins/cppeditor/cppquickfixes.h20
-rw-r--r--src/plugins/cpptools/insertionpointlocator.cpp5
-rw-r--r--src/plugins/cpptools/insertionpointlocator.h7
6 files changed, 490 insertions, 60 deletions
diff --git a/src/plugins/cppeditor/cppeditorplugin.h b/src/plugins/cppeditor/cppeditorplugin.h
index 5a60494bb7..cfeb087fd0 100644
--- a/src/plugins/cppeditor/cppeditorplugin.h
+++ b/src/plugins/cppeditor/cppeditorplugin.h
@@ -145,6 +145,8 @@ private slots:
void test_quickfix_InsertDefFromDecl_templateClass();
void test_quickfix_InsertDefFromDecl_templateFunction();
void test_quickfix_InsertDefFromDecl_notTriggeredForFriendFunc();
+ void test_quickfix_InsertDefsFromDecls_data();
+ void test_quickfix_InsertDefsFromDecls();
void test_quickfix_InsertDeclFromDef();
void test_quickfix_InsertDeclFromDef_templateFuncTypename();
diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp
index 64d969dba1..bc6e4be96e 100644
--- a/src/plugins/cppeditor/cppquickfix_test.cpp
+++ b/src/plugins/cppeditor/cppquickfix_test.cpp
@@ -254,6 +254,10 @@ QuickFixOperationTest::QuickFixOperationTest(const QList<QuickFixTestDocument::P
removeTrailingWhitespace(result);
if (!expectedFailMessage.isEmpty())
QEXPECT_FAIL("", expectedFailMessage.data(), Continue);
+ else if (result != testDocument->m_expectedSource) {
+ qDebug() << "---" << testDocument->m_expectedSource;
+ qDebug() << "+++" << result;
+ }
QCOMPARE(result, testDocument->m_expectedSource);
// Undo the change
@@ -3485,6 +3489,133 @@ void CppEditorPlugin::test_quickfix_InsertDefFromDecl_notTriggeredForFriendFunc(
QuickFixOperationTest(singleDocument(contents, ""), &factory);
}
+void CppEditorPlugin::test_quickfix_InsertDefsFromDecls_data()
+{
+ QTest::addColumn<QByteArrayList>("headers");
+ QTest::addColumn<QByteArrayList>("sources");
+ QTest::addColumn<int>("mode");
+
+ QByteArray origHeader = R"(
+ namespace N {
+ class @C
+ {
+ Q_OBJECT
+ public:
+ friend void ignoredFriend();
+ void ignoredImplemented() {};
+ void ignoredImplemented2(); // Below
+ void ignoredImplemented3(); // In cpp file
+ void funcNotSelected();
+ void funcInline();
+ void funcBelow();
+ void funcCppFile();
+
+ signals:
+ void ignoredSignal();
+ };
+
+ inline void C::ignoredImplemented2() {}
+
+ } // namespace N)";
+ QByteArray origSource = R"(
+ #include "file.h"
+
+ namespace N {
+
+ void C::ignoredImplemented3() {}
+
+ } // namespace N)";
+
+ QByteArray expectedHeader = R"(
+ namespace N {
+ class C
+ {
+ Q_OBJECT
+ public:
+ friend void ignoredFriend();
+ void ignoredImplemented() {};
+ void ignoredImplemented2(); // Below
+ void ignoredImplemented3(); // In cpp file
+ void funcNotSelected();
+ void funcInline()
+ {
+
+ }
+ void funcBelow();
+ void funcCppFile();
+
+ signals:
+ void ignoredSignal();
+ };
+
+ inline void C::ignoredImplemented2() {}
+
+ inline void C::funcBelow()
+ {
+
+ }
+
+ } // namespace N)";
+ QByteArray expectedSource = R"(
+ #include "file.h"
+
+ namespace N {
+
+ void C::ignoredImplemented3() {}
+
+ void C::funcCppFile()
+ {
+
+ }
+
+ } // namespace N)";
+ QTest::addRow("normal case")
+ << QByteArrayList{origHeader, expectedHeader}
+ << QByteArrayList{origSource, expectedSource}
+ << int(InsertDefsFromDecls::Mode::Alternating);
+ QTest::addRow("aborted dialog")
+ << QByteArrayList{origHeader, origHeader}
+ << QByteArrayList{origSource, origSource}
+ << int(InsertDefsFromDecls::Mode::Off);
+
+ origHeader = R"(
+ namespace N {
+ class @C
+ {
+ Q_OBJECT
+ public:
+ friend void ignoredFriend();
+ void ignoredImplemented() {};
+ void ignoredImplemented2(); // Below
+ void ignoredImplemented3(); // In cpp file
+
+ signals:
+ void ignoredSignal();
+ };
+
+ inline void C::ignoredImplemented2() {}
+
+ } // namespace N)";
+ QTest::addRow("no candidates")
+ << QByteArrayList{origHeader, ""}
+ << QByteArrayList{origSource, ""}
+ << int(InsertDefsFromDecls::Mode::Alternating);
+}
+
+void CppEditorPlugin::test_quickfix_InsertDefsFromDecls()
+{
+ QFETCH(QByteArrayList, headers);
+ QFETCH(QByteArrayList, sources);
+ QFETCH(int, mode);
+
+ QList<QuickFixTestDocument::Ptr> testDocuments({
+ QuickFixTestDocument::create("file.h", headers.at(0), headers.at(1)),
+ QuickFixTestDocument::create("file.cpp", sources.at(0), sources.at(1))});
+ InsertDefsFromDecls factory;
+ factory.setMode(static_cast<InsertDefsFromDecls::Mode>(mode));
+ QuickFixOperationTest(testDocuments, &factory);
+}
+
// Function for one of InsertDeclDef section cases
void insertToSectionDeclFromDef(const QByteArray &section, int sectionIndex)
{
diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp
index 71a70c26c7..90283f32e4 100644
--- a/src/plugins/cppeditor/cppquickfixes.cpp
+++ b/src/plugins/cppeditor/cppquickfixes.cpp
@@ -73,7 +73,10 @@
#include <QDir>
#include <QFileInfo>
#include <QFormLayout>
+#include <QGridLayout>
+#include <QHash>
#include <QInputDialog>
+#include <QPair>
#include <QPushButton>
#include <QRegularExpression>
#include <QSharedPointer>
@@ -2991,95 +2994,124 @@ public:
}
}
- void perform() override
+ static void insertDefinition(
+ const CppQuickFixOperation *op,
+ InsertionLocation loc,
+ DefPos defPos,
+ DeclaratorAST *declAST,
+ Declaration *decl,
+ const QString &targetFilePath,
+ ChangeSet *changeSet = nullptr,
+ QList<ChangeSet::Range> *indentRanges = nullptr)
{
- CppRefactoringChanges refactoring(snapshot());
- if (!m_loc.isValid())
- m_loc = insertLocationForMethodDefinition(m_decl, true, NamespaceHandling::Ignore,
- refactoring, m_targetFileName);
- QTC_ASSERT(m_loc.isValid(), return);
+ CppRefactoringChanges refactoring(op->snapshot());
+ if (!loc.isValid())
+ loc = insertLocationForMethodDefinition(decl, true, NamespaceHandling::Ignore,
+ refactoring, targetFilePath);
+ QTC_ASSERT(loc.isValid(), return);
- CppRefactoringFilePtr targetFile = refactoring.file(m_loc.fileName());
+ CppRefactoringFilePtr targetFile = refactoring.file(loc.fileName());
Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview();
oo.showFunctionSignatures = true;
oo.showReturnTypes = true;
oo.showArgumentNames = true;
oo.showEnclosingTemplate = true;
- if (m_defpos == DefPosInsideClass) {
- const int targetPos = targetFile->position(m_loc.line(), m_loc.column());
- ChangeSet target;
- target.replace(targetPos - 1, targetPos, QLatin1String("\n {\n\n}")); // replace ';'
- targetFile->setChangeSet(target);
- targetFile->appendIndentRange(ChangeSet::Range(targetPos, targetPos + 4));
- targetFile->setOpenEditor(true, targetPos);
- targetFile->apply();
-
- // Move cursor inside definition
- QTextCursor c = targetFile->cursor();
- c.setPosition(targetPos);
- c.movePosition(QTextCursor::Down);
- c.movePosition(QTextCursor::EndOfLine);
- editor()->setTextCursor(c);
+ if (defPos == DefPosInsideClass) {
+ const int targetPos = targetFile->position(loc.line(), loc.column());
+ ChangeSet localChangeSet;
+ ChangeSet * const target = changeSet ? changeSet : &localChangeSet;
+ target->replace(targetPos - 1, targetPos, QLatin1String("\n {\n\n}")); // replace ';'
+ const ChangeSet::Range indentRange(targetPos, targetPos + 4);
+ if (indentRanges)
+ indentRanges->append(indentRange);
+ else
+ targetFile->appendIndentRange(indentRange);
+
+ if (!changeSet) {
+ targetFile->setChangeSet(*target);
+ targetFile->setOpenEditor(true, targetPos);
+ targetFile->apply();
+
+ // Move cursor inside definition
+ QTextCursor c = targetFile->cursor();
+ c.setPosition(targetPos);
+ c.movePosition(QTextCursor::Down);
+ c.movePosition(QTextCursor::EndOfLine);
+ op->editor()->setTextCursor(c);
+ }
} else {
// make target lookup context
Document::Ptr targetDoc = targetFile->cppDocument();
- Scope *targetScope = targetDoc->scopeAt(m_loc.line(), m_loc.column());
- LookupContext targetContext(targetDoc, snapshot());
+ Scope *targetScope = targetDoc->scopeAt(loc.line(), loc.column());
+ LookupContext targetContext(targetDoc, op->snapshot());
ClassOrNamespace *targetCoN = targetContext.lookupType(targetScope);
if (!targetCoN)
targetCoN = targetContext.globalNamespace();
// setup rewriting to get minimally qualified names
SubstitutionEnvironment env;
- env.setContext(context());
- env.switchScope(m_decl->enclosingScope());
+ env.setContext(op->context());
+ env.switchScope(decl->enclosingScope());
UseMinimalNames q(targetCoN);
env.enter(&q);
- Control *control = context().bindings()->control().data();
+ Control *control = op->context().bindings()->control().data();
// rewrite the function type
- const FullySpecifiedType tn = rewriteType(m_decl->type(), &env, control);
+ const FullySpecifiedType tn = rewriteType(decl->type(), &env, control);
// rewrite the function name
- if (nameIncludesOperatorName(m_decl->name())) {
- CppRefactoringFilePtr file = refactoring.file(fileName());
- const QString operatorNameText = file->textOf(m_declAST->core_declarator);
+ if (nameIncludesOperatorName(decl->name())) {
+ CppRefactoringFilePtr file = refactoring.file(op->fileName());
+ const QString operatorNameText = file->textOf(declAST->core_declarator);
oo.includeWhiteSpaceInOperatorName = operatorNameText.contains(QLatin1Char(' '));
}
- const QString name = oo.prettyName(LookupContext::minimalName(m_decl, targetCoN,
+ const QString name = oo.prettyName(LookupContext::minimalName(decl, targetCoN,
control));
const QString defText = inlinePrefix(
- m_targetFileName, [this] { return m_defpos == DefPosOutsideClass; })
+ targetFilePath, [defPos] { return defPos == DefPosOutsideClass; })
+ oo.prettyType(tn, name)
+ QLatin1String("\n{\n\n}");
- const int targetPos = targetFile->position(m_loc.line(), m_loc.column());
- const int targetPos2 = qMax(0, targetFile->position(m_loc.line(), 1) - 1);
-
- ChangeSet target;
- target.insert(targetPos, m_loc.prefix() + defText + m_loc.suffix());
- targetFile->setChangeSet(target);
- targetFile->appendIndentRange(ChangeSet::Range(targetPos2, targetPos));
- targetFile->setOpenEditor(true, targetPos);
- targetFile->apply();
-
- // Move cursor inside definition
- QTextCursor c = targetFile->cursor();
- c.setPosition(targetPos);
- c.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor,
- m_loc.prefix().count(QLatin1String("\n")) + 2);
- c.movePosition(QTextCursor::EndOfLine);
- if (m_defpos == DefPosImplementationFile) {
- if (targetFile->editor())
- targetFile->editor()->setTextCursor(c);
- } else {
- editor()->setTextCursor(c);
+ const int targetPos = targetFile->position(loc.line(), loc.column());
+ const int targetPos2 = qMax(0, targetFile->position(loc.line(), 1) - 1);
+
+ ChangeSet localChangeSet;
+ ChangeSet * const target = changeSet ? changeSet : &localChangeSet;
+ target->insert(targetPos, loc.prefix() + defText + loc.suffix());
+ const ChangeSet::Range indentRange(targetPos2, targetPos);
+ if (indentRanges)
+ indentRanges->append(indentRange);
+ else
+ targetFile->appendIndentRange(indentRange);
+
+ if (!changeSet) {
+ targetFile->setChangeSet(*target);
+ targetFile->setOpenEditor(true, targetPos);
+ targetFile->apply();
+
+ // Move cursor inside definition
+ QTextCursor c = targetFile->cursor();
+ c.setPosition(targetPos);
+ c.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor,
+ loc.prefix().count(QLatin1String("\n")) + 2);
+ c.movePosition(QTextCursor::EndOfLine);
+ if (defPos == DefPosImplementationFile) {
+ if (targetFile->editor())
+ targetFile->editor()->setTextCursor(c);
+ } else {
+ op->editor()->setTextCursor(c);
+ }
}
}
}
private:
+ void perform() override
+ {
+ insertDefinition(this, m_loc, m_defpos, m_declAST, m_decl, m_targetFileName);
+ }
+
Declaration *m_decl;
DeclaratorAST *m_declAST;
InsertionLocation m_loc;
@@ -3327,6 +3359,250 @@ QString InsertMemberFromInitialization::getType(
return tpp(type);
}
+class MemberFunctionImplSetting
+{
+public:
+ Symbol *func = nullptr;
+ DefPos defPos = DefPosImplementationFile;
+};
+using MemberFunctionImplSettings = QList<MemberFunctionImplSetting>;
+
+class AddImplementationsDialog : public QDialog
+{
+ Q_DECLARE_TR_FUNCTIONS(AddImplementationsDialog)
+public:
+ AddImplementationsDialog(const QList<Symbol *> &candidates, const Utils::FilePath &implFile)
+ : QDialog(Core::ICore::dialogParent()), m_candidates(candidates)
+ {
+ setWindowTitle(tr("Member Function Implementations"));
+
+ const auto defaultImplTargetComboBox = new QComboBox;
+ QStringList implTargetStrings{tr("None"), tr("Inline"), tr("Outside Class")};
+ if (!implFile.isEmpty())
+ implTargetStrings.append(implFile.fileName());
+ defaultImplTargetComboBox->insertItems(0, implTargetStrings);
+ connect(defaultImplTargetComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this,
+ [this](int index) {
+ for (QComboBox * const cb : m_implTargetBoxes)
+ cb->setCurrentIndex(index);
+ });
+ const auto defaultImplTargetLayout = new QHBoxLayout;
+ defaultImplTargetLayout->addWidget(new QLabel(tr("Default Implementation Location:")));
+ defaultImplTargetLayout->addWidget(defaultImplTargetComboBox);
+
+ const auto candidatesLayout = new QGridLayout;
+ Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview();
+ oo.showFunctionSignatures = true;
+ oo.showReturnTypes = true;
+ for (int i = 0; i < m_candidates.size(); ++i) {
+ const auto implTargetComboBox = new QComboBox;
+ m_implTargetBoxes.append(implTargetComboBox);
+ implTargetComboBox->insertItems(0, implTargetStrings);
+ const Symbol * const func = m_candidates.at(i);
+ candidatesLayout->addWidget(new QLabel(oo.prettyType(func->type(), func->name())),
+ i, 0);
+ candidatesLayout->addWidget(implTargetComboBox, i, 1);
+ }
+
+ const auto buttonBox
+ = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+
+ defaultImplTargetComboBox->setCurrentIndex(implTargetStrings.size() - 1);
+ const auto mainLayout = new QVBoxLayout(this);
+ mainLayout->addLayout(defaultImplTargetLayout);
+ const auto separator = new QFrame();
+ separator->setFrameShape(QFrame::HLine);
+ mainLayout->addWidget(separator);
+ mainLayout->addLayout(candidatesLayout);
+ mainLayout->addWidget(buttonBox);
+ }
+
+ MemberFunctionImplSettings settings() const
+ {
+ QTC_ASSERT(m_candidates.size() == m_implTargetBoxes.size(), return {});
+ MemberFunctionImplSettings settings;
+ for (int i = 0; i < m_candidates.size(); ++i) {
+ MemberFunctionImplSetting setting;
+ const int index = m_implTargetBoxes.at(i)->currentIndex();
+ const bool addImplementation = index != 0;
+ if (!addImplementation)
+ continue;
+ setting.func = m_candidates.at(i);
+ setting.defPos = static_cast<DefPos>(index - 1);
+ settings << setting;
+ }
+ return settings;
+ }
+
+private:
+ const QList<Symbol *> m_candidates;
+ QList<QComboBox *> m_implTargetBoxes;
+};
+
+class InsertDefsOperation: public CppQuickFixOperation
+{
+public:
+ InsertDefsOperation(const CppQuickFixInterface &interface)
+ : CppQuickFixOperation(interface)
+ {
+ setDescription(CppQuickFixFactory::tr("Create Implementations for Member Functions"));
+
+ const QList<AST *> &path = interface.path();
+ if (path.size() < 2)
+ return;
+
+ // Determine if cursor is on a class
+ const SimpleNameAST * const nameAST = path.at(path.size() - 1)->asSimpleName();
+ if (!nameAST || !interface.isCursorOn(nameAST))
+ return;
+ m_classAST = path.at(path.size() - 2)->asClassSpecifier();
+ if (!m_classAST)
+ return;
+
+ const Class * const theClass = m_classAST->symbol;
+ if (!theClass)
+ return;
+
+ // Collect all member functions without an implementation.
+ for (auto it = theClass->memberBegin(); it != theClass->memberEnd(); ++it) {
+ Symbol * const s = *it;
+ if (!s->identifier() || !s->type() || !s->isDeclaration() || s->asFunction())
+ continue;
+ Function * const func = s->type()->asFunctionType();
+ if (!func || func->isSignal() || func->isFriend())
+ continue;
+ if (SymbolFinder().findMatchingDefinition(s, interface.snapshot()))
+ continue;
+ m_declarations << s;
+ }
+ }
+
+ bool isApplicable() const { return !m_declarations.isEmpty(); }
+ void setMode(InsertDefsFromDecls::Mode mode) { m_mode = mode; }
+
+private:
+ void perform() override
+ {
+ QTC_ASSERT(!m_declarations.isEmpty(), return);
+
+ CppRefactoringChanges refactoring(snapshot());
+ const bool isHeaderFile = ProjectFile::isHeader(ProjectFile::classify(fileName()));
+ QString cppFile; // Only set if the class is defined in a header file.
+ if (isHeaderFile) {
+ InsertionPointLocator locator(refactoring);
+ for (const InsertionLocation &location
+ : locator.methodDefinition(m_declarations.first(), false, {})) {
+ if (!location.isValid())
+ continue;
+ const QString fileName = location.fileName();
+ if (ProjectFile::isHeader(ProjectFile::classify(fileName))) {
+ const QString source = CppTools::correspondingHeaderOrSource(fileName);
+ if (!source.isEmpty())
+ cppFile = source;
+ } else {
+ cppFile = fileName;
+ }
+ break;
+ }
+ }
+
+ MemberFunctionImplSettings settings;
+ switch (m_mode) {
+ case InsertDefsFromDecls::Mode::User: {
+ AddImplementationsDialog dlg(m_declarations, Utils::FilePath::fromString(cppFile));
+ if (dlg.exec() == QDialog::Accepted)
+ settings = dlg.settings();
+ break;
+ }
+ case InsertDefsFromDecls::Mode::Alternating: {
+ int defPos = DefPosImplementationFile;
+ const auto incDefPos = [&defPos] {
+ defPos = (defPos + 1) % (DefPosImplementationFile + 2);
+ };
+ for (Symbol * const func : qAsConst(m_declarations)) {
+ incDefPos();
+ if (defPos > DefPosImplementationFile)
+ continue;
+ MemberFunctionImplSetting setting;
+ setting.func = func;
+ setting.defPos = static_cast<DefPos>(defPos);
+ settings << setting;
+ }
+ break;
+ }
+ case InsertDefsFromDecls::Mode::Off:
+ break;
+ }
+
+ if (settings.isEmpty())
+ return;
+
+ class DeclFinder : public ASTVisitor
+ {
+ public:
+ DeclFinder(const CppRefactoringFile *file, const Symbol *func)
+ : ASTVisitor(file->cppDocument()->translationUnit()), m_func(func) {}
+
+ SimpleDeclarationAST *decl() const { return m_decl; }
+
+ private:
+ bool visit(SimpleDeclarationAST *decl) override
+ {
+ if (m_decl)
+ return false;
+ if (decl->symbols && decl->symbols->value == m_func)
+ m_decl = decl;
+ return !m_decl;
+ }
+
+ const Symbol * const m_func;
+ SimpleDeclarationAST *m_decl = nullptr;
+ };
+
+ QHash<QString, QPair<ChangeSet, QList<ChangeSet::Range>>> changeSets;
+ for (const MemberFunctionImplSetting &setting : qAsConst(settings)) {
+ DeclFinder finder(currentFile().data(), setting.func);
+ finder.accept(m_classAST);
+ QTC_ASSERT(finder.decl(), continue);
+ InsertionLocation loc;
+ const QString targetFilePath = setting.defPos == DefPosImplementationFile
+ ? cppFile : fileName();
+ QTC_ASSERT(!targetFilePath.isEmpty(), continue);
+ if (setting.defPos == DefPosInsideClass) {
+ int line, column;
+ currentFile()->lineAndColumn(currentFile()->endOf(finder.decl()), &line, &column);
+ loc = InsertionLocation(fileName(), QString(), QString(), line, column);
+ }
+ auto &changeSet = changeSets[targetFilePath];
+ InsertDefOperation::insertDefinition(
+ this, loc, setting.defPos, finder.decl()->declarator_list->value,
+ setting.func->asDeclaration(),targetFilePath,
+ &changeSet.first, &changeSet.second);
+ }
+ for (auto it = changeSets.cbegin(); it != changeSets.cend(); ++it) {
+ const CppRefactoringFilePtr file = refactoring.file(it.key());
+ for (const ChangeSet::Range &r : it.value().second)
+ file->appendIndentRange(r);
+ file->setChangeSet(it.value().first);
+ file->apply();
+ }
+ }
+
+ ClassSpecifierAST *m_classAST = nullptr;
+ QList<Symbol *> m_declarations;
+ InsertDefsFromDecls::Mode m_mode;
+};
+
+
+void InsertDefsFromDecls::match(const CppQuickFixInterface &interface, QuickFixOperations &result)
+{
+ const auto op = QSharedPointer<InsertDefsOperation>::create(interface);
+ op->setMode(m_mode);
+ if (op->isApplicable())
+ result << op;
+}
namespace {
@@ -7022,6 +7298,7 @@ void createCppQuickFixes()
new InsertDeclFromDef;
new InsertDefFromDecl;
new InsertMemberFromInitialization;
+ new InsertDefsFromDecls;
new MoveFuncDefOutside;
new MoveAllFuncDefOutside;
diff --git a/src/plugins/cppeditor/cppquickfixes.h b/src/plugins/cppeditor/cppquickfixes.h
index 8098861157..633e49599b 100644
--- a/src/plugins/cppeditor/cppquickfixes.h
+++ b/src/plugins/cppeditor/cppquickfixes.h
@@ -408,6 +408,26 @@ private:
};
/*!
+ Adds a definition for any number of member function declarations.
+ */
+class InsertDefsFromDecls : public CppQuickFixFactory
+{
+public:
+ void match(const CppQuickFixInterface &interface,
+ TextEditor::QuickFixOperations &result) override;
+
+ enum class Mode {
+ Off, // Testing: simulates user canceling the dialog
+ Alternating, // Testing: simulates user choosing a different DefPos for every function
+ User // Normal interactive mode
+ };
+ void setMode(Mode mode) { m_mode = mode; }
+
+private:
+ Mode m_mode = Mode::User;
+};
+
+/*!
Extracts the selected code and puts it to a function
*/
class ExtractFunction : public CppQuickFixFactory
diff --git a/src/plugins/cpptools/insertionpointlocator.cpp b/src/plugins/cpptools/insertionpointlocator.cpp
index c92d8bbca8..e006356794 100644
--- a/src/plugins/cpptools/insertionpointlocator.cpp
+++ b/src/plugins/cpptools/insertionpointlocator.cpp
@@ -550,9 +550,8 @@ static InsertionLocation nextToSurroundingDefinitions(Symbol *declaration,
return InsertionLocation(QString::fromUtf8(definitionFunction->fileName()), prefix, suffix, line, column);
}
-QList<InsertionLocation> InsertionPointLocator::methodDefinition(Symbol *declaration,
- bool useSymbolFinder,
- const QString &destinationFile) const
+const QList<InsertionLocation> InsertionPointLocator::methodDefinition(
+ Symbol *declaration, bool useSymbolFinder, const QString &destinationFile) const
{
QList<InsertionLocation> result;
if (!declaration)
diff --git a/src/plugins/cpptools/insertionpointlocator.h b/src/plugins/cpptools/insertionpointlocator.h
index a54f988241..b3ce754260 100644
--- a/src/plugins/cpptools/insertionpointlocator.h
+++ b/src/plugins/cpptools/insertionpointlocator.h
@@ -93,9 +93,10 @@ public:
const CPlusPlus::Class *clazz,
AccessSpec xsSpec) const;
- QList<InsertionLocation> methodDefinition(CPlusPlus::Symbol *declaration,
- bool useSymbolFinder = true,
- const QString &destinationFile = QString()) const;
+ const QList<InsertionLocation> methodDefinition(
+ CPlusPlus::Symbol *declaration,
+ bool useSymbolFinder = true,
+ const QString &destinationFile = QString()) const;
private:
CppRefactoringChanges m_refactoringChanges;