From 293297269f976b3b1a82c306c099fda9b0f095f5 Mon Sep 17 00:00:00 2001
From: Christian Stenger
Date: Thu, 1 Feb 2024 10:13:39 +0100
Subject: [PATCH 0001/1060] Tests: Provide example tasks file
Change-Id: I529102dba9cd259de25d69a527e3ac2a0e1a9380
Reviewed-by: hjk
---
tests/manual/otherfiles/dummy_taskfile.tasks | 65 ++++++++++++++++++++
1 file changed, 65 insertions(+)
create mode 100644 tests/manual/otherfiles/dummy_taskfile.tasks
diff --git a/tests/manual/otherfiles/dummy_taskfile.tasks b/tests/manual/otherfiles/dummy_taskfile.tasks
new file mode 100644
index 00000000000..1317a0e4c19
--- /dev/null
+++ b/tests/manual/otherfiles/dummy_taskfile.tasks
@@ -0,0 +1,65 @@
+ba/Z6xF/M0IIRI2d5pvaSyknCSyOAissFvJYsntwrQ.h 4762 other unused
+/iQTQFzlxBsJGnfJbt5rCA8YH4oe7rqvyW3hCrWO84QN.cpp 4104 error dummy information
+/2Sm4hfyhGRG8TAXhYv874ysHRuEuabzjz1/gdng7MHZIhyp2S.h 9442 other syntax error
+/Oc2S9dMhbZDZymQChSiiv3Brqqp1FzSUUfnxhFHAvnwk3rSbMd.cpp 282 warn missing information
+/igZwSBi65YI9RZCkYucjgnA0nFzyhwQHsR5zIHbCFBz69oSo.h 2266 error missing information
+/Z6hIBPwiXv3lxn2WggqDP62WLthQxPdQmzjSHd.cpp 9289 error unknown error
+sdef/rpx9V404NdbmV/9Ph7jXqAsK7wsB31y6Tx9KIBG.h 8316 other missing information
+/tRdL//67g/paZsnLpdGN4J6q6/RdBYYVXSpP1djxfg3w.cpp 4717 error not found
+/EdL/stJAk2wbrL1V21xUSbfX3OVV5hWDz0O9r6fYsV93yU.h 1894 warn unknown error
+/aAokPAGz8zR6AiBN19mndJRs7w84oQlxUFkBSYrn.cpp 1102 other syntax error
+/6uwjGfQ2o/j5/SEUbs57xxqxIMSl14deuLY7km5oLBc.h 9359 warn unused
+/nBQ8eQ63Sb4HZc5lE2yvWZwck6OSx9zwT9hpzL.cpp 2969 warn syntax error
+sdf/SqzyeibvrCAHNelVI715AtjFC83Q4feZpepvCMr78Kb8.h 3691 error unknown error
+/xhlVpBsiOkm0ZmH01wXXk0QHImeJbcCOF7/M4f.cpp 1038 other unused
+/8gvIBNXwX3l224T/4l75YAzmOvMcyHW/plILha7.h 2525 warn unused
+/uu46Fvj6IwAptMDDaN23HzoyBQ61Ls917LOoWMZfhLX.cpp 4573 other dummy information
+/rJcO7WZR2fGNYO3pTvnyXOFELxAfsuSCffRb/aMfm5.h 5148 warn missing information
+/Srj2krdE/UPV1OYlZSYOu6w10kgzBscAfqw//9776pSGa8L76.cpp 4690 warn dummy information
+/VlJRNSuHVpjFqCQVVWPf7R4gOSoRuGPxtGpO/xjuLceiHf.h 9683 error syntax error
+sdf/Q/YgTtEdgAj9PzbPyBF604wEZSYXrciun69ut57e.cpp 8272 error not found
+/rapyyxw6cXoUd9XHWCx4V4IwO9g0LlVyXFmh5sXJk8xvuZCq.h 4329 warn syntax error
+/TVizFLbV7VZVeX56p3Mc2olEeNWSEIpI9iZaBhmgm/.cpp 692 error not found
+sdf/Yaoc6iF24WOdamUb5j2/SDfeBoW5U92nig/6XkpE3pyEX9m.h 8336 warn syntax error
+/rnUQ3Ew7J8yWckFBbfMg8qAMuEMgTIv0UryeYMw.cpp 8612 error unused
+/6AJYrSTsALywqx8TinQxxsfu7Qu19xgb4Shm3uxUVmOC.h 3948 warn dummy information
+/owg0bC1TF0ImRR7acppvAJhdBT6cUadw8696pOVgpx2oa40.cpp 4850 error not found
+//LbsNqHaAIdYRDMwBKr7nmZ1b4njJTb1h1WSl60F.h 4893 warn missing information
+/ivHIukAf5HoFD6cxs34JkKnHrlrxD73WRi7UvfzBQt.cpp 7724 warn dummy information
+/Tivy85ab71MZu5bta8ordtMzAa38Y8LAZcs61eJLHNXP.h 7556 error unused
+sdf/RZEHytd0Kmq5VUCoLqNAhAI3hlZlxltDTDdWU3WV2yuktyfg.cpp 6721 error dummy information
+/ENk8j0noHhsZbTlqRJ46cDhjZ7PHDhfa7te8n1OsXgVO.h 5374 error missing information
+/edEInJsvjm3dqakU9oyYMT7Nybmet4L6olT/dedWLDltWEjz.cpp 9621 other missing information
+/q1MlgSvwv8Ikq4Bjcqa0X9OY/q1GRQ5ARhejOOZKu15XDVb7/M.h 1068 error dummy information
+/EvcJN3d5iiIP4H2TLC6ssHeQoTUf/HHC1/gq8m.cpp 7062 warn dummy information
+sdfxc/XISMZsHJSJNL1jKTYE1ZyJK9ekBnx4WpyrVdNjmRasxm.h 8513 error unknown error
+/uJWF20pUZPpedDMfGNz0cCCwIymTW1JtxK5ut4fHScwq.cpp 1234 error syntax error
+/kgQCRBmcKWNd966rPIz4IPfekDqxjQm1eAZ7/Y3Vl8.h 476 error unknown error
+/I3aGZ2vLcuMjmcUI40eB4XTwsYQ34sSIgcj28SRPVRyu8.cpp 2175 error dummy information
+/q3M0KxZi3Umo2CWe9EzDqMo4LcNVeQhrnV2Yu7zR.h 3969 error syntax error
+/tcVCRlsoFo61oIMMwP8seWKpKfC8KskferbtgI.cpp 10 warn not found
+sdf/wQSRjPZZJwzREWemLQ96RisR0x2HKpVvZTohxwWRVevBIrtN2.h 5836 error unknown error
+/cgMEkzRs9dJfJZvejXqppDjyhbT8gs6/Q07mSJPOQD.cpp 3882 error unknown error
+/CBipJCtJq5JHOtz5njHmH6eM5dvPjRQ3KO0PDXUIghI3rO6pm.h 3818 error not found
+/ucFWsPMwDK3d8OuKH2d5kfrHTsz2Nlw8wZV4MfNzm.cpp 1303 error missing information
+/eiWeH306mDV9AZKSqRV/h2OhJlmXuvPUuLrmUoDfvK.h 887 warn dummy information
+/nSaLMeLNeFgWkppVcacpGzQbnwDgnHy43/P0zDb6y/4PWkIyKq.cpp 7644 error unknown error
+/BF1mxdQbpB7spT8uj/XPjkxRyKJXO53v0RDs3c.h 4909 other unknown error
+/HLpMI/AdAabKQJgZ3CfoZ3IkUH8d2AKak6WME/Ff2.cpp 92 error dummy information
+/rM2GH8fkUddRFYRc4ZAxoNmZVnccOQ13sRTAMp.h 2487 error dummy information
+/pQ4QD264U3z1H1odOUGSuDpvq9FIMlonytSsNpUnVkBMTl.cpp 835 error syntax error
+/olSx6ZAKh7x43uFC6TeSqfdRsnNHozb1Oa8jgHuAx.h 8006 error unknown error
+/36QcXAGehPbcSpreu8Dps1jTYaGLhYokbga3Ez.cpp 1219 warn missing information
+/kLtmnkB88UvQNB2tNpQkEIRBPk2w9VQY4XKWwkcNsGYN.h 9212 warn dummy information
+/HdhlYekmcIsnI4752ng8bT/sJEzpP/rbqrOLJ47.cpp 2818 warn syntax error
+/nSQVu9In4/D3Mo2JQfjLuMzz49ZC1K/OQkO0t6Vibrl.h 6785 error missing information
+/uOyhgr9Y5cvev6HeW9GAiy2g6QMDzUBABLNb5KIHLaJiKHsUXu.cpp 5833 warn syntax error
+/vej4BOeRTak5ILrWzxPhYLXCx7akC8LXkVKwbJyok4r80tstgr.h 1863 other syntax error
+/jGz0VyhokwjE4mmQSMpPoKK5teActVfmL2CGupQT39.cpp 175 warn unknown error
+/PCcGDSa7h208wlJz1wa81nREtA/Kx/ZAMraQQ9QYTg.h 7977 other unused
+/OaEQzW35Ng2yeSqs41f6ji/RWSnx71G4BlmlWX.cpp 3650 warn not found
+/1e6Ric7K9WElXkBE6ymSMPXtFuu86QbI8mYAEy63c1Asp/hO.h 3725 error unknown error
+/qaPzTGefWpHBNGX3XWne5zBkkLCBiMi3mm9x2cIU9l9szD.cpp 1338 warn syntax error
+/YAPg7LHxjrOeBJ4CZBVkoXR6lKI7jrSV5bD7kfXOAf8mzM.h 3389 error unused
+/IMjUnSaqSsKs5xCzhDcrgk1saAcr2wKnJZ3tyxI6VbSeX.cpp 2404 other unknown error
+/5rQ9UzSyJFvYZhyI9sItDZHnBrANcz84rtDfDfJh.h 7293 warn not found
From c9ea3c6a51a4d1c3fa734ce1ec3afeee8d7ae367 Mon Sep 17 00:00:00 2001
From: Eike Ziller
Date: Tue, 6 Feb 2024 15:01:00 +0100
Subject: [PATCH 0002/1060] OutputWindow: Add "clear" to all context menus
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Change-Id: I989b15eb602d3224813510eacf020e3fdc90c650
Reviewed-by: Orgad Shaneh
Reviewed-by: André Hartmann
Reviewed-by:
---
src/plugins/coreplugin/outputwindow.cpp | 18 +++++++++++++
src/plugins/coreplugin/outputwindow.h | 2 ++
src/plugins/vcsbase/vcsoutputwindow.cpp | 35 +++++++------------------
3 files changed, 29 insertions(+), 26 deletions(-)
diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp
index 7e32bcc807d..ca0de974560 100644
--- a/src/plugins/coreplugin/outputwindow.cpp
+++ b/src/plugins/coreplugin/outputwindow.cpp
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -195,6 +196,8 @@ void OutputWindow::handleLink(const QPoint &pos)
d->formatter.handleLink(href);
}
+void OutputWindow::adaptContextMenu(QMenu *, const QPoint &) {}
+
void OutputWindow::mouseReleaseEvent(QMouseEvent *e)
{
if (d->linksActive && d->mouseButtonPressed == Qt::LeftButton)
@@ -279,6 +282,21 @@ void OutputWindow::wheelEvent(QWheelEvent *e)
updateMicroFocus();
}
+void OutputWindow::contextMenuEvent(QContextMenuEvent *event)
+{
+ QMenu *menu = createStandardContextMenu(event->pos());
+ menu->setAttribute(Qt::WA_DeleteOnClose);
+
+ adaptContextMenu(menu, event->pos());
+
+ menu->addSeparator();
+ QAction *clearAction = menu->addAction(Tr::tr("Clear"));
+ connect(clearAction, &QAction::triggered, this, [this] { clear(); });
+ clearAction->setEnabled(!document()->isEmpty());
+
+ menu->popup(event->globalPos());
+}
+
void OutputWindow::setBaseFont(const QFont &newFont)
{
float zoom = fontZoom();
diff --git a/src/plugins/coreplugin/outputwindow.h b/src/plugins/coreplugin/outputwindow.h
index 83681a988e4..cfcea8aae05 100644
--- a/src/plugins/coreplugin/outputwindow.h
+++ b/src/plugins/coreplugin/outputwindow.h
@@ -75,6 +75,7 @@ public slots:
protected:
virtual void handleLink(const QPoint &pos);
+ virtual void adaptContextMenu(QMenu *menu, const QPoint &pos);
private:
QMimeData *createMimeDataFromSelection() const override;
@@ -85,6 +86,7 @@ private:
void resizeEvent(QResizeEvent *e) override;
void showEvent(QShowEvent *) override;
void wheelEvent(QWheelEvent *e) override;
+ void contextMenuEvent(QContextMenuEvent *event) override;
using QPlainTextEdit::setFont; // call setBaseFont instead, which respects the zoom factor
void enableUndoRedo();
diff --git a/src/plugins/vcsbase/vcsoutputwindow.cpp b/src/plugins/vcsbase/vcsoutputwindow.cpp
index 4b6eab6fb17..fdd91a5ed0d 100644
--- a/src/plugins/vcsbase/vcsoutputwindow.cpp
+++ b/src/plugins/vcsbase/vcsoutputwindow.cpp
@@ -79,7 +79,7 @@ public:
const FilePath &repository);
protected:
- void contextMenuEvent(QContextMenuEvent *event) override;
+ void adaptContextMenu(QMenu *menu, const QPoint &pos) override;
void handleLink(const QPoint &pos) override;
private:
@@ -138,15 +138,15 @@ QString OutputWindowPlainTextEdit::identifierUnderCursor(const QPoint &widgetPos
return endPos > startPos ? block.mid(startPos, endPos - startPos) : QString();
}
-void OutputWindowPlainTextEdit::contextMenuEvent(QContextMenuEvent *event)
+void OutputWindowPlainTextEdit::adaptContextMenu(QMenu *menu, const QPoint &pos)
{
- const QString href = anchorAt(event->pos());
- QMenu *menu = href.isEmpty() ? createStandardContextMenu(event->pos()) : new QMenu;
- menu->setAttribute(Qt::WA_DeleteOnClose);
+ const QString href = anchorAt(pos);
+ if (!href.isEmpty())
+ menu->clear();
// Add 'open file'
FilePath repo;
- const QString token = identifierUnderCursor(event->pos(), &repo);
+ const QString token = identifierUnderCursor(pos, &repo);
if (!repo.isEmpty() && !href.isEmpty())
m_parser->fillLinkContextMenu(menu, repo, href);
QAction *openAction = nullptr;
@@ -157,26 +157,9 @@ void OutputWindowPlainTextEdit::contextMenuEvent(QContextMenuEvent *event)
if (repo.isFile()) {
menu->addSeparator();
openAction = menu->addAction(Tr::tr("Open \"%1\"").arg(repo.nativePath()));
- openAction->setData(repo.absoluteFilePath().toVariant());
- }
- }
- QAction *clearAction = nullptr;
- if (href.isEmpty()) {
- // Add 'clear'
- menu->addSeparator();
- clearAction = menu->addAction(Tr::tr("Clear"));
- }
-
- // Run
- QAction *action = menu->exec(event->globalPos());
- if (action) {
- if (action == clearAction) {
- clear();
- return;
- }
- if (action == openAction) {
- const auto fileName = FilePath::fromVariant(action->data());
- EditorManager::openEditor(fileName);
+ connect(openAction, &QAction::triggered, this, [fp = repo.absoluteFilePath()] {
+ EditorManager::openEditor(fp);
+ });
}
}
}
From e2756fde8b3fb1eb6d9750b24d7cbd4154f9d4d1 Mon Sep 17 00:00:00 2001
From: Christian Kandeler
Date: Mon, 5 Feb 2024 16:57:56 +0100
Subject: [PATCH 0003/1060] CppEditor: Add quickfix for converting a function
call
... to a Qt meta-method invocation.
Fixes: QTCREATORBUG-15972
Change-Id: Id84c83c5832cef32a877a451b0931ec47d2afe9d
Reviewed-by: Christian Stenger
---
src/plugins/cppeditor/cppquickfix_test.cpp | 87 ++++++++++
src/plugins/cppeditor/cppquickfix_test.h | 3 +
src/plugins/cppeditor/cppquickfixes.cpp | 193 ++++++++++++++++++---
src/plugins/cppeditor/cppquickfixes.h | 9 +
4 files changed, 267 insertions(+), 25 deletions(-)
diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp
index b0064ab790a..80a4af36db1 100644
--- a/src/plugins/cppeditor/cppquickfix_test.cpp
+++ b/src/plugins/cppeditor/cppquickfix_test.cpp
@@ -9468,4 +9468,91 @@ void QuickfixTest::testMoveComments()
QuickFixOperationTest(documents, &factory, {}, {}, failMessage);
}
+void QuickfixTest::testConvertToMetaMethodInvocation_data()
+{
+ QTest::addColumn("input");
+ QTest::addColumn("expected");
+
+ // ^ marks the cursor locations.
+ // $ marks the replacement regions.
+ // The quoted string in the comment is the data tag.
+ // The rest of the comment is the replacement string.
+ const QByteArray allCases = R"(
+class C {
+public:
+ C() {
+ $this->^aSignal()$; // "signal from region on pointer to object" QMetaObject::invokeMethod(this, "aSignal")
+ C c;
+ $c.^aSignal()$; // "signal from region on object value" QMetaObject::invokeMethod(&c, "aSignal")
+ $(new C)->^aSignal()$; // "signal from region on expression" QMetaObject::invokeMethod((new C), "aSignal")
+ $emit this->^aSignal()$; // "signal from region, with emit" QMetaObject::invokeMethod(this, "aSignal")
+ $Q_EMIT this->^aSignal()$; // "signal from region, with Q_EMIT" QMetaObject::invokeMethod(this, "aSignal")
+ $this->^aSlot()$; // "slot from region" QMetaObject::invokeMethod(this, "aSlot")
+ $this->^noArgs()$; // "Q_SIGNAL, no arguments" QMetaObject::invokeMethod(this, "noArgs")
+ $this->^oneArg(0)$; // "Q_SLOT, one argument" QMetaObject::invokeMethod(this, "oneArg", Q_ARG(int, 0))
+ $this->^twoArgs(0, c)$; // "Q_INVOKABLE, two arguments" QMetaObject::invokeMethod(this, "twoArgs", Q_ARG(int, 0), Q_ARG(C, c))
+ this->^notInvokable(); // "not invokable"
+ }
+
+signals:
+ void aSignal();
+
+private slots:
+ void aSlot();
+
+private:
+ Q_SIGNAL void noArgs();
+ Q_SLOT void oneArg(int index);
+ Q_INVOKABLE void twoArgs(int index, const C &value);
+ void notInvokable();
+};
+)";
+
+ qsizetype nextCursor = allCases.indexOf('^');
+ while (nextCursor != -1) {
+ const int commentStart = allCases.indexOf("//", nextCursor);
+ QVERIFY(commentStart != -1);
+ const int tagStart = allCases.indexOf('"', commentStart + 2);
+ QVERIFY(tagStart != -1);
+ const int tagEnd = allCases.indexOf('"', tagStart + 1);
+ QVERIFY(tagEnd != -1);
+ QByteArray input = allCases;
+ QByteArray output = allCases;
+ input.replace(nextCursor, 1, "@");
+ const QByteArray tag = allCases.mid(tagStart + 1, tagEnd - tagStart - 1);
+ const int prevNewline = allCases.lastIndexOf('\n', nextCursor);
+ const int regionStart = allCases.lastIndexOf('$', nextCursor);
+ bool hasReplacement = false;
+ if (regionStart != -1 && regionStart > prevNewline) {
+ const int regionEnd = allCases.indexOf('$', regionStart + 1);
+ QVERIFY(regionEnd != -1);
+ const int nextNewline = allCases.indexOf('\n', tagEnd);
+ QVERIFY(nextNewline != -1);
+ const QByteArray replacement
+ = allCases.mid(tagEnd + 1, nextNewline - tagEnd - 1).trimmed();
+ output.replace(regionStart, regionEnd - regionStart, replacement);
+ hasReplacement = true;
+ }
+ static const auto matcher = [](char c) { return c == '^' || c == '$'; };
+ input.removeIf(matcher);
+ if (hasReplacement) {
+ output.removeIf(matcher);
+ output.prepend("#include \n\n");
+ } else {
+ output.clear();
+ }
+ QTest::newRow(tag.data()) << input << output;
+ nextCursor = allCases.indexOf('^', nextCursor + 1);
+ }
+}
+
+void QuickfixTest::testConvertToMetaMethodInvocation()
+{
+ QFETCH(QByteArray, input);
+ QFETCH(QByteArray, expected);
+
+ ConvertToMetaMethodCall factory;
+ QuickFixOperationTest({CppTestDocument::create("file.cpp", input, expected)}, &factory);
+}
+
} // namespace CppEditor::Internal::Tests
diff --git a/src/plugins/cppeditor/cppquickfix_test.h b/src/plugins/cppeditor/cppquickfix_test.h
index cc589f1908a..e677d88af24 100644
--- a/src/plugins/cppeditor/cppquickfix_test.h
+++ b/src/plugins/cppeditor/cppquickfix_test.h
@@ -224,6 +224,9 @@ private slots:
void testMoveComments_data();
void testMoveComments();
+
+ void testConvertToMetaMethodInvocation_data();
+ void testConvertToMetaMethodInvocation();
};
} // namespace Tests
diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp
index 74862772e5a..b2f01eaad47 100644
--- a/src/plugins/cppeditor/cppquickfixes.cpp
+++ b/src/plugins/cppeditor/cppquickfixes.cpp
@@ -221,8 +221,10 @@ Namespace *isNamespaceFunction(const LookupContext &context, Function *function)
}
// Given include is e.g. "afile.h" or (quotes/angle brackets included!).
-void insertNewIncludeDirective(const QString &include, CppRefactoringFilePtr file,
- const Document::Ptr &cppDocument)
+static void insertNewIncludeDirective(const QString &include,
+ CppRefactoringFilePtr file,
+ const Document::Ptr &cppDocument,
+ ChangeSet &changes)
{
// Find optimal position
unsigned newLinesToPrepend = 0;
@@ -245,10 +247,7 @@ void insertNewIncludeDirective(const QString &include, CppRefactoringFilePtr fil
const QString textToInsert = prependedNewLines + includeLine + appendedNewLines;
// Insert
- ChangeSet changes;
changes.insert(insertPosition, textToInsert);
- file->setChangeSet(changes);
- file->apply();
}
bool nameIncludesOperatorName(const Name *name)
@@ -322,6 +321,32 @@ QString nameString(const NameAST *name)
return CppCodeStyleSettings::currentProjectCodeStyleOverview().prettyName(name->name);
}
+static FullySpecifiedType typeOfExpr(const ExpressionAST *expr,
+ const CppRefactoringFilePtr &file,
+ const Snapshot &snapshot,
+ const LookupContext &context)
+{
+ TypeOfExpression typeOfExpression;
+ typeOfExpression.init(file->cppDocument(), snapshot, context.bindings());
+ Scope *scope = file->scopeAt(expr->firstToken());
+ const QList result = typeOfExpression(
+ file->textOf(expr).toUtf8(), scope, TypeOfExpression::Preprocess);
+ if (result.isEmpty())
+ return {};
+
+ SubstitutionEnvironment env;
+ env.setContext(context);
+ env.switchScope(result.first().scope());
+ ClassOrNamespace *con = typeOfExpression.context().lookupType(scope);
+ if (!con)
+ con = typeOfExpression.context().globalNamespace();
+ UseMinimalNames q(con);
+ env.enter(&q);
+
+ Control *control = context.bindings()->control().get();
+ return rewriteType(result.first().type(), &env, control);
+}
+
// FIXME: Needs to consider the scope at the insertion site.
QString declFromExpr(const TypeOrExpr &typeOrExpr, const CallAST *call, const NameAST *varName,
const Snapshot &snapshot, const LookupContext &context,
@@ -338,25 +363,7 @@ QString declFromExpr(const TypeOrExpr &typeOrExpr, const CallAST *call, const Na
return {};
};
const auto getTypeOfExpr = [&](const ExpressionAST *expr) -> FullySpecifiedType {
- TypeOfExpression typeOfExpression;
- typeOfExpression.init(file->cppDocument(), snapshot, context.bindings());
- Scope *scope = file->scopeAt(expr->firstToken());
- const QList result = typeOfExpression(
- file->textOf(expr).toUtf8(), scope, TypeOfExpression::Preprocess);
- if (result.isEmpty())
- return {};
-
- SubstitutionEnvironment env;
- env.setContext(context);
- env.switchScope(result.first().scope());
- ClassOrNamespace *con = typeOfExpression.context().lookupType(scope);
- if (!con)
- con = typeOfExpression.context().globalNamespace();
- UseMinimalNames q(con);
- env.enter(&q);
-
- Control *control = context.bindings()->control().get();
- return rewriteType(result.first().type(), &env, control);
+ return typeOfExpr(expr, file, snapshot, context);
};
const Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview();
@@ -1791,7 +1798,10 @@ void AddIncludeForUndefinedIdentifierOp::perform()
CppRefactoringChanges refactoring(snapshot());
CppRefactoringFilePtr file = refactoring.cppFile(filePath());
- insertNewIncludeDirective(m_include, file, semanticInfo().doc);
+ ChangeSet changes;
+ insertNewIncludeDirective(m_include, file, semanticInfo().doc, changes);
+ file->setChangeSet(changes);
+ file->apply();
}
AddForwardDeclForUndefinedIdentifierOp::AddForwardDeclForUndefinedIdentifierOp(
@@ -9801,6 +9811,138 @@ void MoveFunctionComments::doMatch(const CppQuickFixInterface &interface,
}
}
+namespace {
+class ConvertToMetaMethodCallOp : public CppQuickFixOperation
+{
+public:
+ ConvertToMetaMethodCallOp(const CppQuickFixInterface &interface, CallAST *callAst)
+ : CppQuickFixOperation(interface), m_callAst(callAst)
+ {
+ setDescription(Tr::tr("Convert function call to Qt meta-method invocation"));
+ }
+
+private:
+ void perform() override
+ {
+ // Construct the argument list.
+ Overview ov;
+ QStringList arguments;
+ for (ExpressionListAST *it = m_callAst->expression_list; it; it = it->next) {
+ if (!it->value)
+ return;
+ const FullySpecifiedType argType
+ = typeOfExpr(it->value, currentFile(), snapshot(), context());
+ if (!argType.isValid())
+ return;
+ arguments << QString::fromUtf8("Q_ARG(%1, %2)")
+ .arg(ov.prettyType(argType), currentFile()->textOf(it->value));
+ }
+ QString argsString = arguments.join(", ");
+ if (!argsString.isEmpty())
+ argsString.prepend(", ");
+
+ // Construct the replace string.
+ const auto memberAccessAst = m_callAst->base_expression->asMemberAccess();
+ QTC_ASSERT(memberAccessAst, return);
+ QString baseExpr = currentFile()->textOf(memberAccessAst->base_expression);
+ const FullySpecifiedType baseExprType
+ = typeOfExpr(memberAccessAst->base_expression, currentFile(), snapshot(), context());
+ if (!baseExprType.isValid())
+ return;
+ if (!baseExprType->asPointerType())
+ baseExpr.prepend('&');
+ const QString functionName = currentFile()->textOf(memberAccessAst->member_name);
+ const QString qMetaObject = "QMetaObject";
+ const QString newCall = QString::fromUtf8("%1::invokeMethod(%2, \"%3\"%4)")
+ .arg(qMetaObject, baseExpr, functionName, argsString);
+
+ // Determine the start and end positions of the replace operation.
+ // If the call is preceded by an "emit" keyword, that one has to be removed as well.
+ int firstToken = m_callAst->firstToken();
+ if (firstToken > 0)
+ switch (semanticInfo().doc->translationUnit()->tokenKind(firstToken - 1)) {
+ case T_EMIT: case T_Q_EMIT: --firstToken; break;
+ default: break;
+ }
+ const TranslationUnit *const tu = semanticInfo().doc->translationUnit();
+ const int startPos = tu->getTokenPositionInDocument(firstToken, textDocument());
+ const int endPos = tu->getTokenPositionInDocument(m_callAst->lastToken(), textDocument());
+
+ // Replace the old call with the new one.
+ ChangeSet changes;
+ changes.replace(startPos, endPos, newCall);
+
+ // Insert include for QMetaObject, if necessary.
+ const Identifier qMetaObjectId(qPrintable(qMetaObject), qMetaObject.size());
+ Scope * const scope = currentFile()->scopeAt(firstToken);
+ const QList results = context().lookup(&qMetaObjectId, scope);
+ bool isDeclared = false;
+ for (const LookupItem &item : results) {
+ if (Symbol *declaration = item.declaration(); declaration && declaration->asClass()) {
+ isDeclared = true;
+ break;
+ }
+ }
+ if (!isDeclared) {
+ insertNewIncludeDirective('<' + qMetaObject + '>', currentFile(), semanticInfo().doc,
+ changes);
+ }
+
+ // Apply the changes.
+ currentFile()->setChangeSet(changes);
+ currentFile()->apply();
+ }
+
+ const CallAST * const m_callAst;
+};
+} // namespace
+
+void ConvertToMetaMethodCall::doMatch(const CppQuickFixInterface &interface,
+ TextEditor::QuickFixOperations &result)
+{
+ const Document::Ptr &cppDoc = interface.currentFile()->cppDocument();
+ const QList path = ASTPath(cppDoc)(interface.cursor());
+ if (path.isEmpty())
+ return;
+
+ // Are we on a member function call?
+ CallAST *callAst = nullptr;
+ for (auto it = path.crbegin(); it != path.crend(); ++it) {
+ if ((callAst = (*it)->asCall()))
+ break;
+ }
+ if (!callAst || !callAst->base_expression)
+ return;
+ ExpressionAST *baseExpr = nullptr;
+ const NameAST *nameAst = nullptr;
+ if (const MemberAccessAST * const ast = callAst->base_expression->asMemberAccess()) {
+ baseExpr = ast->base_expression;
+ nameAst = ast->member_name;
+ }
+ if (!baseExpr || !nameAst || !nameAst->name)
+ return;
+
+ // Locate called function and check whether it is invokable.
+ Scope *scope = cppDoc->globalNamespace();
+ for (auto it = path.crbegin(); it != path.crend(); ++it) {
+ if (const CompoundStatementAST * const stmtAst = (*it)->asCompoundStatement()) {
+ scope = stmtAst->symbol;
+ break;
+ }
+ }
+ const LookupContext context(cppDoc, interface.snapshot());
+ TypeOfExpression exprType;
+ exprType.setExpandTemplates(true);
+ exprType.init(cppDoc, interface.snapshot());
+ const QList typeMatches = exprType(callAst->base_expression, cppDoc, scope);
+ for (const LookupItem &item : typeMatches) {
+ if (const auto func = item.type()->asFunctionType(); func && func->methodKey()) {
+ result << new ConvertToMetaMethodCallOp(interface, callAst);
+ return;
+ }
+ }
+}
+
void createCppQuickFixes()
{
new AddIncludeForUndefinedIdentifier;
@@ -9860,6 +10002,7 @@ void createCppQuickFixes()
new GenerateConstructor;
new ConvertCommentStyle;
new MoveFunctionComments;
+ new ConvertToMetaMethodCall;
}
void destroyCppQuickFixes()
diff --git a/src/plugins/cppeditor/cppquickfixes.h b/src/plugins/cppeditor/cppquickfixes.h
index 953cfa5468e..99904ffcb19 100644
--- a/src/plugins/cppeditor/cppquickfixes.h
+++ b/src/plugins/cppeditor/cppquickfixes.h
@@ -617,5 +617,14 @@ private:
TextEditor::QuickFixOperations &result) override;
};
+//! Converts a normal function call into a meta method invocation, if the functions is
+//! marked as invokable.
+class ConvertToMetaMethodCall : public CppQuickFixFactory
+{
+private:
+ void doMatch(const CppQuickFixInterface &interface,
+ TextEditor::QuickFixOperations &result) override;
+};
+
} // namespace Internal
} // namespace CppEditor
From 971bcb1a5abd396819510644e55ef437978adcd5 Mon Sep 17 00:00:00 2001
From: David Schulz
Date: Fri, 9 Feb 2024 06:11:27 +0100
Subject: [PATCH 0004/1060] TextEditor: fix multi text cursor unindent via
backspace
Change-Id: Iec2e9251b977ccbd7433009ac3e706a9327c704c
Reviewed-by: Marcus Tillmanns
---
src/plugins/texteditor/texteditor.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp
index 1ed6d0db513..1184749e86e 100644
--- a/src/plugins/texteditor/texteditor.cpp
+++ b/src/plugins/texteditor/texteditor.cpp
@@ -6846,7 +6846,7 @@ void TextEditorWidgetPrivate::handleBackspaceKey()
if (cursorWithinSnippet)
m_snippetOverlay->accept();
cursorWithinSnippet = false;
- q->unindent();
+ c = m_document->unindent(MultiTextCursor({c})).mainCursor();
}
handled = true;
}
From 7a055a2f0ad7bd99eb5629f8ce6dfa5ae7a27080 Mon Sep 17 00:00:00 2001
From: Eike Ziller
Date: Tue, 6 Feb 2024 15:21:13 +0100
Subject: [PATCH 0005/1060] OutputWindow: Add "Save Contents" to context menu
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
And give individual output windows the option to set a default file name.
Change-Id: If3090063055c1b37f4f2d63b971fe0476f11806e
Reviewed-by: Orgad Shaneh
Reviewed-by: André Hartmann
Reviewed-by:
Reviewed-by: Tasuku Suzuki
---
src/plugins/coreplugin/outputwindow.cpp | 14 ++++++++++++++
src/plugins/coreplugin/outputwindow.h | 2 ++
src/plugins/projectexplorer/appoutputpane.cpp | 2 ++
.../projectexplorer/compileoutputwindow.cpp | 2 ++
4 files changed, 20 insertions(+)
diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp
index ca0de974560..dbbcdde585a 100644
--- a/src/plugins/coreplugin/outputwindow.cpp
+++ b/src/plugins/coreplugin/outputwindow.cpp
@@ -73,6 +73,8 @@ public:
QTimer scrollTimer;
QElapsedTimer lastMessage;
QHash> taskPositions;
+ //: default file name suggested for saving text from output views
+ QString outputFileNameHint{Tr::tr("output.txt")};
};
} // namespace Internal
@@ -289,6 +291,13 @@ void OutputWindow::contextMenuEvent(QContextMenuEvent *event)
adaptContextMenu(menu, event->pos());
+ menu->addSeparator();
+ QAction *saveAction = menu->addAction(Tr::tr("Save Contents..."));
+ connect(saveAction, &QAction::triggered, this, [this] {
+ QFileDialog::saveFileContent(toPlainText().toUtf8(), d->outputFileNameHint);
+ });
+ saveAction->setEnabled(!document()->isEmpty());
+
menu->addSeparator();
QAction *clearAction = menu->addAction(Tr::tr("Clear"));
connect(clearAction, &QAction::triggered, this, [this] { clear(); });
@@ -368,6 +377,11 @@ void OutputWindow::updateFilterProperties(
filterNewContent();
}
+void OutputWindow::setOutputFileNameHint(const QString &fileName)
+{
+ d->outputFileNameHint = fileName;
+}
+
void OutputWindow::filterNewContent()
{
QTextBlock lastBlock = document()->findBlockByNumber(d->lastFilteredBlockNumber);
diff --git a/src/plugins/coreplugin/outputwindow.h b/src/plugins/coreplugin/outputwindow.h
index cfcea8aae05..cd44e5678e9 100644
--- a/src/plugins/coreplugin/outputwindow.h
+++ b/src/plugins/coreplugin/outputwindow.h
@@ -67,6 +67,8 @@ public:
bool regexp,
bool isInverted);
+ void setOutputFileNameHint(const QString &fileName);
+
signals:
void wheelZoom();
diff --git a/src/plugins/projectexplorer/appoutputpane.cpp b/src/plugins/projectexplorer/appoutputpane.cpp
index 898acaba2a9..94e2694acc2 100644
--- a/src/plugins/projectexplorer/appoutputpane.cpp
+++ b/src/plugins/projectexplorer/appoutputpane.cpp
@@ -429,6 +429,8 @@ void AppOutputPane::createNewOutputWindow(RunControl *rc)
ow->setWindowIcon(Icons::WINDOW.icon());
ow->setWordWrapEnabled(m_settings.wrapOutput);
ow->setMaxCharCount(m_settings.maxCharCount);
+ //: file name suggested for saving application output, %1 = run configuration display name
+ ow->setOutputFileNameHint(Tr::tr("application-output-%1.txt").arg(rc->displayName()));
auto updateFontSettings = [ow] {
ow->setBaseFont(TextEditor::TextEditorSettings::fontSettings().font());
diff --git a/src/plugins/projectexplorer/compileoutputwindow.cpp b/src/plugins/projectexplorer/compileoutputwindow.cpp
index 8d2b12983bd..c5255d127f5 100644
--- a/src/plugins/projectexplorer/compileoutputwindow.cpp
+++ b/src/plugins/projectexplorer/compileoutputwindow.cpp
@@ -61,6 +61,8 @@ CompileOutputWindow::CompileOutputWindow(QAction *cancelBuildAction) :
m_outputWindow->setReadOnly(true);
m_outputWindow->setUndoRedoEnabled(false);
m_outputWindow->setMaxCharCount(Core::Constants::DEFAULT_MAX_CHAR_COUNT);
+ //: file name suggested for saving compile output
+ m_outputWindow->setOutputFileNameHint(Tr::tr("compile-output.txt"));
Utils::ProxyAction *cancelBuildProxyButton =
Utils::ProxyAction::proxyActionWithIcon(cancelBuildAction,
From 1af555ad09be169bebc7525e4bb7e10ad4de271d Mon Sep 17 00:00:00 2001
From: Christian Kandeler
Date: Thu, 8 Feb 2024 15:00:55 +0100
Subject: [PATCH 0006/1060] ClangCodeModel: Let users configure the clangd
index location
Fixes: QTCREATORBUG-27346
Change-Id: I9bc59f759682e70b761c0f22a011868008fc0360
Reviewed-by:
Reviewed-by: Qt CI Bot
Reviewed-by: hjk
Reviewed-by: Eike Ziller
---
.../clangmodelmanagersupport.cpp | 21 ++++----
src/plugins/coreplugin/coreplugin.cpp | 4 ++
.../cppeditor/cppcodemodelsettings.cpp | 32 +++++++++++
src/plugins/cppeditor/cppcodemodelsettings.h | 38 ++++++++-----
.../cppeditor/cppcodemodelsettingspage.cpp | 53 ++++++++++++++++++-
5 files changed, 122 insertions(+), 26 deletions(-)
diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
index 53d0e6f3784..3c3fc18c911 100644
--- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
+++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp
@@ -45,6 +45,7 @@
#include
#include
#include
+#include
#include
#include
@@ -472,17 +473,15 @@ void ClangModelManagerSupport::connectToWidgetsMarkContextMenuRequested(QWidget
}
}
-static FilePath getJsonDbDir(const Project *project)
+static FilePath getJsonDbDir(Project *project)
{
- static const QString dirName(".qtc_clangd");
- if (!project) {
- const QString sessionDirName = FileUtils::fileSystemFriendlyName(
- SessionManager::activeSession());
- return ICore::userResourcePath() / dirName / sessionDirName; // TODO: Make configurable?
- }
- if (const Target * const target = project->activeTarget()) {
- if (const BuildConfiguration * const bc = target->activeBuildConfiguration())
- return bc->buildDirectory() / dirName;
+ if (!project)
+ return ClangdSettings::instance().sessionIndexPath(*globalMacroExpander());
+ if (const Target *const target = project->activeTarget()) {
+ if (const BuildConfiguration *const bc = target->activeBuildConfiguration()) {
+ return ClangdSettings(ClangdProjectSettings(project).settings())
+ .projectIndexPath(*bc->macroExpander());
+ }
}
return {};
}
@@ -696,7 +695,7 @@ ClangdClient *ClangModelManagerSupport::clientWithProject(const Project *project
void ClangModelManagerSupport::updateStaleIndexEntries()
{
QHash lastModifiedCache;
- for (const Project * const project : ProjectManager::projects()) {
+ for (Project * const project : ProjectManager::projects()) {
const FilePath jsonDbDir = getJsonDbDir(project);
if (jsonDbDir.isEmpty())
continue;
diff --git a/src/plugins/coreplugin/coreplugin.cpp b/src/plugins/coreplugin/coreplugin.cpp
index 49ca2fec8af..2ff53a68d04 100644
--- a/src/plugins/coreplugin/coreplugin.cpp
+++ b/src/plugins/coreplugin/coreplugin.cpp
@@ -226,6 +226,10 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
Tr::tr("The directory where %1 finds its pre-installed resources.")
.arg(QGuiApplication::applicationDisplayName()),
[] { return ICore::resourcePath().toString(); });
+ expander->registerVariable("IDE:UserResourcePath",
+ Tr::tr("The directory where %1 puts custom user data.")
+ .arg(QGuiApplication::applicationDisplayName()),
+ [] { return ICore::userResourcePath().toString(); });
expander->registerPrefix("CurrentDate:", Tr::tr("The current date (QDate formatstring)."),
[](const QString &fmt) { return QDate::currentDate().toString(fmt); });
expander->registerPrefix("CurrentTime:", Tr::tr("The current time (QTime formatstring)."),
diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp
index db6231cfe99..1c294af4150 100644
--- a/src/plugins/cppeditor/cppcodemodelsettings.cpp
+++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp
@@ -15,10 +15,12 @@
#include
#include
+#include
#include
#include
#include
+#include
#include
#include
#include
@@ -45,6 +47,8 @@ static Key clangdSettingsKey() { return "ClangdSettings"; }
static Key useClangdKey() { return "UseClangdV7"; }
static Key clangdPathKey() { return "ClangdPath"; }
static Key clangdIndexingKey() { return "ClangdIndexing"; }
+static Key clangdProjectIndexPathKey() { return "ClangdProjectIndexPath"; }
+static Key clangdSessionIndexPathKey() { return "ClangdSessionIndexPath"; }
static Key clangdIndexingPriorityKey() { return "ClangdIndexingPriority"; }
static Key clangdHeaderSourceSwitchModeKey() { return "ClangdHeaderSourceSwitchMode"; }
static Key clangdCompletionRankingModelKey() { return "ClangdCompletionRankingModel"; }
@@ -248,6 +252,16 @@ QString ClangdSettings::rankingModelToDisplayString(CompletionRankingModel model
QTC_ASSERT(false, return {});
}
+QString ClangdSettings::defaultProjectIndexPathTemplate()
+{
+ return QDir::toNativeSeparators("%{BuildConfig:BuildDirectory:FilePath}/.qtc_clangd");
+}
+
+QString ClangdSettings::defaultSessionIndexPathTemplate()
+{
+ return QDir::toNativeSeparators("%{IDE:UserResourcePath}/.qtc_clangd/%{Session:FileBaseName}");
+}
+
ClangdSettings &ClangdSettings::instance()
{
static ClangdSettings settings;
@@ -318,6 +332,16 @@ FilePath ClangdSettings::clangdFilePath() const
return fallbackClangdFilePath();
}
+FilePath ClangdSettings::projectIndexPath(const Utils::MacroExpander &expander) const
+{
+ return FilePath::fromUserInput(expander.expand(m_data.projectIndexPathTemplate));
+}
+
+FilePath ClangdSettings::sessionIndexPath(const Utils::MacroExpander &expander) const
+{
+ return FilePath::fromUserInput(expander.expand(m_data.sessionIndexPathTemplate));
+}
+
bool ClangdSettings::sizeIsOkay(const Utils::FilePath &fp) const
{
return !sizeThresholdEnabled() || sizeThresholdInKb() * 1024 >= fp.fileSize();
@@ -559,6 +583,10 @@ Store ClangdSettings::Data::toMap() const
map.insertValueWithDefault(clangdIndexingPriorityKey(),
int(indexingPriority),
int(DefaultIndexingPriority));
+ map.insertValueWithDefault(clangdProjectIndexPathKey(), projectIndexPathTemplate,
+ defaultProjectIndexPathTemplate());
+ map.insertValueWithDefault(clangdSessionIndexPathKey(), sessionIndexPathTemplate,
+ defaultSessionIndexPathTemplate());
map.insertValueWithDefault(clangdHeaderSourceSwitchModeKey(),
int(headerSourceSwitchMode),
@@ -610,6 +638,10 @@ void ClangdSettings::Data::fromMap(const Store &map)
const auto it = map.find(clangdIndexingKey());
if (it != map.end() && !it->toBool())
indexingPriority = IndexingPriority::Off;
+ projectIndexPathTemplate
+ = map.value(clangdProjectIndexPathKey(), defaultProjectIndexPathTemplate()).toString();
+ sessionIndexPathTemplate
+ = map.value(clangdSessionIndexPathKey(), defaultSessionIndexPathTemplate()).toString();
headerSourceSwitchMode = HeaderSourceSwitchMode(
map.value(clangdHeaderSourceSwitchModeKey(), int(DefaultHeaderSourceSwitchMode)).toInt());
completionRankingModel = CompletionRankingModel(
diff --git a/src/plugins/cppeditor/cppcodemodelsettings.h b/src/plugins/cppeditor/cppcodemodelsettings.h
index b4f8ac7269d..df0b81d9ca1 100644
--- a/src/plugins/cppeditor/cppcodemodelsettings.h
+++ b/src/plugins/cppeditor/cppcodemodelsettings.h
@@ -17,6 +17,7 @@
#include
namespace ProjectExplorer { class Project; }
+namespace Utils { class MacroExpander; }
namespace CppEditor {
@@ -92,6 +93,8 @@ public:
static QString headerSourceSwitchModeToDisplayString(HeaderSourceSwitchMode mode);
static QString rankingModelToCmdLineString(CompletionRankingModel model);
static QString rankingModelToDisplayString(CompletionRankingModel model);
+ static QString defaultProjectIndexPathTemplate();
+ static QString defaultSessionIndexPathTemplate();
class CPPEDITOR_EXPORT Data
{
@@ -103,6 +106,8 @@ public:
{
return s1.useClangd == s2.useClangd
&& s1.executableFilePath == s2.executableFilePath
+ && s1.projectIndexPathTemplate == s2.projectIndexPathTemplate
+ && s1.sessionIndexPathTemplate == s2.sessionIndexPathTemplate
&& s1.sessionsWithOneClangd == s2.sessionsWithOneClangd
&& s1.customDiagnosticConfigs == s2.customDiagnosticConfigs
&& s1.diagnosticConfigId == s2.diagnosticConfigId
@@ -119,13 +124,28 @@ public:
}
friend bool operator!=(const Data &s1, const Data &s2) { return !(s1 == s2); }
- static int defaultCompletionResults();
-
Utils::FilePath executableFilePath;
QStringList sessionsWithOneClangd;
ClangDiagnosticConfigs customDiagnosticConfigs;
Utils::Id diagnosticConfigId;
+ int workerThreadLimit = DefaultWorkerThreadLimit;
+ int documentUpdateThreshold = DefaultDocumentUpdateThreshold;
+ qint64 sizeThresholdInKb = DefaultSizeThresholdInKb;
+ bool useClangd = DefaultUseClangd;
+ IndexingPriority indexingPriority = DefaultIndexingPriority;
+ QString projectIndexPathTemplate = defaultProjectIndexPathTemplate();
+ QString sessionIndexPathTemplate = defaultSessionIndexPathTemplate();
+ HeaderSourceSwitchMode headerSourceSwitchMode = DefaultHeaderSourceSwitchMode;
+ CompletionRankingModel completionRankingModel = DefaultCompletionRankingModel;
+ bool autoIncludeHeaders = DefaultAutoIncludeHeaders;
+ bool sizeThresholdEnabled = DefaultSizeThresholdEnabled;
+ bool haveCheckedHardwareReqirements = false;
+ int completionResults = defaultCompletionResults();
+
+ private:
+ static int defaultCompletionResults();
+
static constexpr auto DefaultWorkerThreadLimit = 0;
static constexpr auto DefaultDocumentUpdateThreshold = 500;
static constexpr auto DefaultSizeThresholdInKb = 1024ll;
@@ -135,18 +155,6 @@ public:
static constexpr auto DefaultCompletionRankingModel = CompletionRankingModel::Default;
static constexpr auto DefaultAutoIncludeHeaders = false;
static constexpr auto DefaultSizeThresholdEnabled = false;
-
- int workerThreadLimit = DefaultWorkerThreadLimit;
- int documentUpdateThreshold = DefaultDocumentUpdateThreshold;
- qint64 sizeThresholdInKb = DefaultSizeThresholdInKb;
- bool useClangd = DefaultUseClangd;
- IndexingPriority indexingPriority = DefaultIndexingPriority;
- HeaderSourceSwitchMode headerSourceSwitchMode = DefaultHeaderSourceSwitchMode;
- CompletionRankingModel completionRankingModel = DefaultCompletionRankingModel;
- bool autoIncludeHeaders = DefaultAutoIncludeHeaders;
- bool sizeThresholdEnabled = DefaultSizeThresholdEnabled;
- bool haveCheckedHardwareReqirements = false;
- int completionResults = defaultCompletionResults();
};
ClangdSettings(const Data &data) : m_data(data) {}
@@ -163,6 +171,8 @@ public:
static void setCustomDiagnosticConfigs(const ClangDiagnosticConfigs &configs);
Utils::FilePath clangdFilePath() const;
IndexingPriority indexingPriority() const { return m_data.indexingPriority; }
+ Utils::FilePath projectIndexPath(const Utils::MacroExpander &expander) const;
+ Utils::FilePath sessionIndexPath(const Utils::MacroExpander &expander) const;
HeaderSourceSwitchMode headerSourceSwitchMode() const { return m_data.headerSourceSwitchMode; }
CompletionRankingModel completionRankingModel() const { return m_data.completionRankingModel; }
bool autoIncludeHeaders() const { return m_data.autoIncludeHeaders; }
diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp
index bc47a78c9df..b4a19ccaae6 100644
--- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp
+++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp
@@ -18,11 +18,13 @@
#include
#include
+#include
#include
#include
#include
#include
#include
+#include
#include
#include
@@ -36,6 +38,7 @@
#include
#include
#include
+#include
#include
#include
@@ -220,6 +223,8 @@ signals:
private:
QCheckBox m_useClangdCheckBox;
QComboBox m_indexingComboBox;
+ Utils::FancyLineEdit m_projectIndexPathTemplateLineEdit;
+ Utils::FancyLineEdit m_sessionIndexPathTemplateLineEdit;
QComboBox m_headerSourceSwitchComboBox;
QComboBox m_completionRankingModelComboBox;
QCheckBox m_autoIncludeHeadersCheckBox;
@@ -249,6 +254,12 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD
"cores unused.
"
"Normal Priority: Reduced priority compared to interactive work.
"
"Low Priority: Same priority as other clangd work.
");
+ const QString projectIndexPathToolTip = Tr::tr(
+ "The location of the per-project clangd index."
+ "This is also where the compile_commands.json file will go.");
+ const QString sessionIndexPathToolTip = Tr::tr(
+ "The location of the per-session clangd index.
"
+ "This is also where the compile_commands.json file will go.");
const QString headerSourceSwitchToolTip = Tr::tr(
"
The C/C++ backend to use for switching between header and source files.
"
"While the clangd implementation has more capabilities than the built-in "
@@ -296,6 +307,8 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD
m_indexingComboBox.setCurrentIndex(m_indexingComboBox.count() - 1);
}
m_indexingComboBox.setToolTip(indexingToolTip);
+ m_projectIndexPathTemplateLineEdit.setText(settings.data().projectIndexPathTemplate);
+ m_sessionIndexPathTemplateLineEdit.setText(settings.data().sessionIndexPathTemplate);
using SwitchMode = ClangdSettings::HeaderSourceSwitchMode;
for (SwitchMode mode : {SwitchMode::BuiltinOnly, SwitchMode::ClangdOnly, SwitchMode::Both}) {
m_headerSourceSwitchComboBox.addItem(
@@ -360,6 +373,33 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD
indexingPriorityLabel->setToolTip(indexingToolTip);
formLayout->addRow(indexingPriorityLabel, indexingPriorityLayout);
+ for (const auto &[text, edit, toolTip, defaultValue] :
+ {std::make_tuple(Tr::tr("Per-project index location:"),
+ &m_projectIndexPathTemplateLineEdit,
+ projectIndexPathToolTip,
+ ClangdSettings::defaultProjectIndexPathTemplate()),
+ std::make_tuple(Tr::tr("Per-session index location:"),
+ &m_sessionIndexPathTemplateLineEdit,
+ sessionIndexPathToolTip,
+ ClangdSettings::defaultSessionIndexPathTemplate())}) {
+ if (isForProject && edit == &m_sessionIndexPathTemplateLineEdit)
+ continue;
+
+ const auto chooser = new Utils::VariableChooser(edit);
+ chooser->addSupportedWidget(edit);
+ chooser->addMacroExpanderProvider([] { return Utils::globalMacroExpander(); });
+
+ const auto resetButton = new QPushButton(Tr::tr("Reset"));
+ connect(resetButton, &QPushButton::clicked, [e = edit, v = defaultValue] { e->setText(v); });
+ const auto layout = new QHBoxLayout;
+ const auto label = new QLabel(text);
+ label->setToolTip(toolTip);
+ edit->setToolTip(toolTip);
+ layout->addWidget(edit);
+ layout->addWidget(resetButton);
+ formLayout->addRow(label, layout);
+ }
+
const auto headerSourceSwitchLayout = new QHBoxLayout;
headerSourceSwitchLayout->addWidget(&m_headerSourceSwitchComboBox);
headerSourceSwitchLayout->addStretch(1);
@@ -530,6 +570,10 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD
this, &ClangdSettingsWidget::settingsDataChanged);
connect(&m_indexingComboBox, &QComboBox::currentIndexChanged,
this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_projectIndexPathTemplateLineEdit, &QLineEdit::textChanged,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_sessionIndexPathTemplateLineEdit, &QLineEdit::textChanged,
+ this, &ClangdSettingsWidget::settingsDataChanged);
connect(&m_headerSourceSwitchComboBox, &QComboBox::currentIndexChanged,
this, &ClangdSettingsWidget::settingsDataChanged);
connect(&m_completionRankingModelComboBox, &QComboBox::currentIndexChanged,
@@ -559,6 +603,8 @@ ClangdSettings::Data ClangdSettingsWidget::settingsData() const
data.executableFilePath = m_clangdChooser.filePath();
data.indexingPriority = ClangdSettings::IndexingPriority(
m_indexingComboBox.currentData().toInt());
+ data.projectIndexPathTemplate = m_projectIndexPathTemplateLineEdit.text();
+ data.sessionIndexPathTemplate = m_sessionIndexPathTemplateLineEdit.text();
data.headerSourceSwitchMode = ClangdSettings::HeaderSourceSwitchMode(
m_headerSourceSwitchComboBox.currentData().toInt());
data.completionRankingModel = ClangdSettings::CompletionRankingModel(
@@ -641,9 +687,14 @@ public:
m_settings.setSettings(m_widget.settingsData());
});
- connect(&m_widget, &ClangdSettingsWidget::settingsDataChanged, this, [this] {
+ const auto timer = new QTimer(this);
+ timer->setSingleShot(true);
+ timer->setInterval(5000);
+ connect(timer, &QTimer::timeout, this, [this] {
m_settings.setSettings(m_widget.settingsData());
});
+ connect(&m_widget, &ClangdSettingsWidget::settingsDataChanged,
+ timer, qOverload<>(&QTimer::start));
}
private:
From b39b1925189416585933c017e189d04d6e4c478d Mon Sep 17 00:00:00 2001
From: Marcus Tillmanns
Date: Thu, 25 Jan 2024 12:21:48 +0100
Subject: [PATCH 0007/1060] ExtensionSystem: Refactor PluginSpec
Splits the functionality between plugin type specific and general.
Allows Plugins to be loaded after the first pass, e.g. for Lua scripted
plugins.
Change-Id: If2712817a672c49d554fdc308250cb06ca7eb3f8
Reviewed-by: Eike Ziller
---
src/libs/extensionsystem/CMakeLists.txt | 2 +-
src/libs/extensionsystem/extensionsystem.qbs | 1 -
src/libs/extensionsystem/optionsparser.cpp | 17 +-
src/libs/extensionsystem/pluginmanager.cpp | 176 +++---
src/libs/extensionsystem/pluginmanager.h | 2 +
src/libs/extensionsystem/pluginmanager_p.h | 8 +-
src/libs/extensionsystem/pluginspec.cpp | 569 +++++++++---------
src/libs/extensionsystem/pluginspec.h | 171 ++++--
src/libs/extensionsystem/pluginspec_p.h | 107 ----
src/libs/extensionsystem/pluginview.cpp | 8 +-
.../coreplugin/plugininstallwizard.cpp | 4 +-
.../pluginspec/testspecs/spec_wrong2.json | 1 +
.../pluginspec/testspecs/spec_wrong3.json | 1 +
.../pluginspec/testspecs/spec_wrong4.json | 1 +
.../pluginspec/testspecs/spec_wrong5.json | 1 +
.../pluginspec/tst_pluginspec.cpp | 290 ++++-----
16 files changed, 678 insertions(+), 681 deletions(-)
delete mode 100644 src/libs/extensionsystem/pluginspec_p.h
diff --git a/src/libs/extensionsystem/CMakeLists.txt b/src/libs/extensionsystem/CMakeLists.txt
index fb836631d93..c8e37668060 100644
--- a/src/libs/extensionsystem/CMakeLists.txt
+++ b/src/libs/extensionsystem/CMakeLists.txt
@@ -11,7 +11,7 @@ add_qtc_library(ExtensionSystem
pluginerroroverview.cpp pluginerroroverview.h
pluginerrorview.cpp pluginerrorview.h
pluginmanager.cpp pluginmanager.h pluginmanager_p.h
- pluginspec.cpp pluginspec.h pluginspec_p.h
+ pluginspec.cpp pluginspec.h
pluginview.cpp pluginview.h
EXPLICIT_MOC
pluginmanager.h
diff --git a/src/libs/extensionsystem/extensionsystem.qbs b/src/libs/extensionsystem/extensionsystem.qbs
index 8748c27ba69..72fe2f4c3cf 100644
--- a/src/libs/extensionsystem/extensionsystem.qbs
+++ b/src/libs/extensionsystem/extensionsystem.qbs
@@ -29,7 +29,6 @@ QtcLibrary {
"pluginmanager_p.h",
"pluginspec.cpp",
"pluginspec.h",
- "pluginspec_p.h",
"pluginview.cpp",
"pluginview.h",
]
diff --git a/src/libs/extensionsystem/optionsparser.cpp b/src/libs/extensionsystem/optionsparser.cpp
index 205442488e6..dd9d03944a2 100644
--- a/src/libs/extensionsystem/optionsparser.cpp
+++ b/src/libs/extensionsystem/optionsparser.cpp
@@ -6,7 +6,6 @@
#include "extensionsystemtr.h"
#include "pluginmanager.h"
#include "pluginmanager_p.h"
-#include "pluginspec_p.h"
#include
@@ -119,7 +118,7 @@ bool OptionsParser::checkForTestOptions()
} else {
m_pmPrivate->testSpecs.emplace_back(spec, args);
}
- } else {
+ } else {
if (m_errorString)
*m_errorString = Tr::tr("The plugin \"%1\" does not exist.").arg(pluginName);
m_hasError = true;
@@ -177,7 +176,7 @@ bool OptionsParser::checkForLoadOption()
if (nextToken(RequiredToken)) {
if (m_currentArg == QLatin1String("all")) {
for (PluginSpec *spec : std::as_const(m_pmPrivate->pluginSpecs))
- spec->d->setForceEnabled(true);
+ spec->setForceEnabled(true);
m_isDependencyRefreshNeeded = true;
} else {
PluginSpec *spec = m_pmPrivate->pluginByName(m_currentArg);
@@ -186,7 +185,7 @@ bool OptionsParser::checkForLoadOption()
*m_errorString = Tr::tr("The plugin \"%1\" does not exist.").arg(m_currentArg);
m_hasError = true;
} else {
- spec->d->setForceEnabled(true);
+ spec->setForceEnabled(true);
m_isDependencyRefreshNeeded = true;
}
}
@@ -202,7 +201,7 @@ bool OptionsParser::checkForNoLoadOption()
if (nextToken(RequiredToken)) {
if (m_currentArg == QLatin1String("all")) {
for (PluginSpec *spec : std::as_const(m_pmPrivate->pluginSpecs))
- spec->d->setForceDisabled(true);
+ spec->setForceDisabled(true);
m_isDependencyRefreshNeeded = true;
} else {
PluginSpec *spec = m_pmPrivate->pluginByName(m_currentArg);
@@ -211,10 +210,10 @@ bool OptionsParser::checkForNoLoadOption()
*m_errorString = Tr::tr("The plugin \"%1\" does not exist.").arg(m_currentArg);
m_hasError = true;
} else {
- spec->d->setForceDisabled(true);
+ spec->setForceDisabled(true);
// recursively disable all plugins that require this plugin
for (PluginSpec *dependantSpec : PluginManager::pluginsRequiringPlugin(spec))
- dependantSpec->d->setForceDisabled(true);
+ dependantSpec->setForceDisabled(true);
m_isDependencyRefreshNeeded = true;
}
}
@@ -292,10 +291,10 @@ bool OptionsParser::checkForUnknownOption()
void OptionsParser::forceDisableAllPluginsExceptTestedAndForceEnabled()
{
for (const PluginManagerPrivate::TestSpec &testSpec : m_pmPrivate->testSpecs)
- testSpec.pluginSpec->d->setForceEnabled(true);
+ testSpec.pluginSpec->setForceEnabled(true);
for (PluginSpec *spec : std::as_const(m_pmPrivate->pluginSpecs)) {
if (!spec->isForceEnabled() && !spec->isRequired())
- spec->d->setForceDisabled(true);
+ spec->setForceDisabled(true);
}
}
diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp
index fcb3062faa9..43b8f3d2fa5 100644
--- a/src/libs/extensionsystem/pluginmanager.cpp
+++ b/src/libs/extensionsystem/pluginmanager.cpp
@@ -8,7 +8,6 @@
#include "optionsparser.h"
#include "pluginmanager_p.h"
#include "pluginspec.h"
-#include "pluginspec_p.h"
#include
@@ -35,6 +34,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -327,6 +327,11 @@ void PluginManager::loadPluginsAtRuntime(const QSet &plugins)
d->loadPluginsAtRuntime(plugins);
}
+void PluginManager::addPlugins(const QVector &specs)
+{
+ d->addPlugins(specs);
+}
+
/*!
Returns \c true if any plugin has errors even though it is enabled.
Most useful to call after loadPlugins().
@@ -903,14 +908,6 @@ QVector PluginManager::loadQueue()
//============PluginManagerPrivate===========
-/*!
- \internal
-*/
-PluginSpec *PluginManagerPrivate::createSpec()
-{
- return new PluginSpec();
-}
-
/*!
\internal
*/
@@ -935,14 +932,6 @@ void PluginManagerPrivate::setGlobalSettings(QtcSettings *s)
globalSettings->setParent(this);
}
-/*!
- \internal
-*/
-PluginSpecPrivate *PluginManagerPrivate::privateSpec(PluginSpec *spec)
-{
- return spec->d;
-}
-
void PluginManagerPrivate::startDelayedInitialize()
{
Utils::setMimeStartupPhase(MimeStartupPhase::PluginsDelayedInitializing);
@@ -954,8 +943,8 @@ void PluginManagerPrivate::startDelayedInitialize()
delayedInitializeQueue.pop();
NANOTRACE_SCOPE(specName, specName + "::delayedInitialized");
profilingReport(">delayedInitialize", spec);
- bool delay = spec->d->delayedInitialize();
- profilingReport("d->performanceData.delayedInitialize);
+ bool delay = spec->delayedInitialize();
+ profilingReport("performanceData().delayedInitialize);
if (delay) // give UI a bit of breathing space, but prevent user interaction
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
}
@@ -1068,10 +1057,8 @@ void PluginManagerPrivate::checkForDuplicatePlugins()
if (spec->isEffectivelyEnabled() && other->isEffectivelyEnabled()) {
const QString error = Tr::tr(
"Multiple versions of the same plugin have been found.");
- spec->d->hasError = true;
- spec->d->errorString = error;
- other->d->hasError = true;
- other->d->errorString = error;
+ spec->setError(error);
+ other->setError(error);
}
} else {
seen.insert(spec->name(), spec);
@@ -1403,7 +1390,7 @@ void PluginManagerPrivate::loadPlugins()
delayedInitializeQueue.push(spec);
} else {
// Plugin initialization failed, so cleanup after it
- spec->d->kill();
+ spec->kill();
}
});
}
@@ -1421,10 +1408,23 @@ void PluginManagerPrivate::loadPlugins()
void PluginManagerPrivate::loadPluginsAtRuntime(const QSet &plugins)
{
QTC_CHECK(allOf(plugins, [](PluginSpec *spec) { return spec->isSoftLoadable(); }));
- // load the plugins ordered by dependency
+
+ // load the plugins and their dependencies (if possible) ordered by dependency
const QList queue = filtered(loadQueue(), [&plugins](PluginSpec *spec) {
- return plugins.contains(spec);
+ // Is the current plugin already running, or not soft loadable?
+ if (spec->state() == PluginSpec::State::Running || !spec->isSoftLoadable())
+ return false;
+
+ // Is the current plugin in the list of plugins to load?
+ if (plugins.contains(spec))
+ return true;
+
+ // Is the current plugin a dependency of any of the plugins we want to load?
+ return plugins.contains(spec) || Utils::anyOf(plugins, [spec](PluginSpec *other) {
+ return other->requiresAny({spec});
+ });
});
+
std::queue localDelayedInitializeQueue;
for (PluginSpec *spec : queue)
loadPlugin(spec, PluginSpec::Loaded);
@@ -1434,12 +1434,12 @@ void PluginManagerPrivate::loadPluginsAtRuntime(const QSet &plugin
[this](PluginSpec *spec) { loadPlugin(spec, PluginSpec::Running); });
Utils::reverseForeach(queue, [](PluginSpec *spec) {
if (spec->state() == PluginSpec::Running) {
- const bool delay = spec->d->delayedInitialize();
+ const bool delay = spec->delayedInitialize();
if (delay)
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
} else {
// Plugin initialization failed, so cleanup after it
- spec->d->kill();
+ spec->kill();
}
});
emit q->pluginsChanged();
@@ -1494,17 +1494,17 @@ bool PluginManagerPrivate::loadQueue(PluginSpec *spec,
return true;
// check for circular dependencies
if (circularityCheckQueue.contains(spec)) {
- spec->d->hasError = true;
- spec->d->errorString = Tr::tr("Circular dependency detected:");
- spec->d->errorString += QLatin1Char('\n');
+ QString errorString = Tr::tr("Circular dependency detected:");
+ errorString += QLatin1Char('\n');
int index = circularityCheckQueue.indexOf(spec);
for (int i = index; i < circularityCheckQueue.size(); ++i) {
const PluginSpec *depSpec = circularityCheckQueue.at(i);
- spec->d->errorString.append(Tr::tr("%1 (%2) depends on")
- .arg(depSpec->name(), depSpec->version()));
- spec->d->errorString += QLatin1Char('\n');
+ errorString.append(
+ Tr::tr("%1 (%2) depends on").arg(depSpec->name(), depSpec->version()));
+ errorString += QLatin1Char('\n');
}
- spec->d->errorString.append(Tr::tr("%1 (%2)").arg(spec->name(), spec->version()));
+ errorString.append(Tr::tr("%1 (%2)").arg(spec->name(), spec->version()));
+ spec->setError(errorString);
return false;
}
circularityCheckQueue.append(spec);
@@ -1523,10 +1523,9 @@ bool PluginManagerPrivate::loadQueue(PluginSpec *spec,
continue;
PluginSpec *depSpec = it.value();
if (!loadQueue(depSpec, queue, circularityCheckQueue)) {
- spec->d->hasError = true;
- spec->d->errorString =
+ spec->setError(
Tr::tr("Cannot load plugin because dependency failed to load: %1 (%2)\nReason: %3")
- .arg(depSpec->name(), depSpec->version(), depSpec->errorString());
+ .arg(depSpec->name(), depSpec->version(), depSpec->errorString()));
return false;
}
}
@@ -1619,9 +1618,9 @@ void PluginManagerPrivate::checkForProblematicPlugins()
dialog.addButton(Tr::tr("Continue"), QMessageBox::RejectRole);
dialog.exec();
if (dialog.clickedButton() == disableButton) {
- spec->d->setForceDisabled(true);
+ spec->setForceDisabled(true);
for (PluginSpec *other : dependents)
- other->d->setForceDisabled(true);
+ other->setForceDisabled(true);
enableDependenciesIndirectly();
}
}
@@ -1664,15 +1663,15 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
case PluginSpec::Running: {
NANOTRACE_SCOPE(specName, specName + "::extensionsInitialized");
profilingReport(">initializeExtensions", spec);
- spec->d->initializeExtensions();
+ spec->initializeExtensions();
profilingReport("d->performanceData.extensionsInitialized);
+ &spec->performanceData().extensionsInitialized);
return;
}
case PluginSpec::Deleted:
profilingReport(">delete", spec);
- spec->d->kill();
+ spec->kill();
profilingReport("state() != destState) {
- spec->d->hasError = true;
- spec->d->errorString =
- Tr::tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3")
- .arg(depSpec->name(), depSpec->version(), depSpec->errorString());
+ spec->setError(
+ Tr::tr(
+ "Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3")
+ .arg(depSpec->name(), depSpec->version(), depSpec->errorString()));
return;
}
}
@@ -1698,20 +1697,20 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
case PluginSpec::Loaded: {
NANOTRACE_SCOPE(specName, specName + "::load");
profilingReport(">loadLibrary", spec);
- spec->d->loadLibrary();
- profilingReport("d->performanceData.load);
+ spec->loadLibrary();
+ profilingReport("performanceData().load);
break;
}
case PluginSpec::Initialized: {
NANOTRACE_SCOPE(specName, specName + "::initialize");
profilingReport(">initializePlugin", spec);
- spec->d->initializePlugin();
- profilingReport("d->performanceData.initialize);
+ spec->initializePlugin();
+ profilingReport("performanceData().initialize);
break;
}
case PluginSpec::Stopped:
profilingReport(">stop", spec);
- if (spec->d->stop() == IPlugin::AsynchronousShutdown) {
+ if (spec->stop() == IPlugin::AsynchronousShutdown) {
asynchronousPlugins << spec;
connect(spec->plugin(), &IPlugin::asynchronousShutdownFinished, this, [this, spec] {
asynchronousPlugins.remove(spec);
@@ -1753,45 +1752,24 @@ static const QStringList pluginFiles(const QStringList &pluginPaths)
return pluginFiles;
}
-/*!
- \internal
-*/
-void PluginManagerPrivate::readPluginPaths()
+void PluginManagerPrivate::addPlugins(const QVector &specs)
{
- qDeleteAll(pluginSpecs);
- pluginSpecs.clear();
- pluginCategories.clear();
+ pluginSpecs += specs;
- // default
- pluginCategories.insert(QString(), QVector());
-
- // from the file system
- for (const QString &pluginFile : pluginFiles(pluginPaths)) {
- PluginSpec *spec = PluginSpec::read(pluginFile);
- if (spec) // Qt Creator plugin
- pluginSpecs.append(spec);
- }
- // static
- for (const QStaticPlugin &plugin : QPluginLoader::staticPlugins()) {
- PluginSpec *spec = PluginSpec::read(plugin);
- if (spec) // Qt Creator plugin
- pluginSpecs.append(spec);
- }
-
- for (PluginSpec *spec : pluginSpecs) {
+ for (PluginSpec *spec : specs) {
// defaultDisabledPlugins and defaultEnabledPlugins from install settings
// is used to override the defaults read from the plugin spec
if (spec->isEnabledByDefault() && defaultDisabledPlugins.contains(spec->name())) {
- spec->d->setEnabledByDefault(false);
- spec->d->setEnabledBySettings(false);
+ spec->setEnabledByDefault(false);
+ spec->setEnabledBySettings(false);
} else if (!spec->isEnabledByDefault() && defaultEnabledPlugins.contains(spec->name())) {
- spec->d->setEnabledByDefault(true);
- spec->d->setEnabledBySettings(true);
+ spec->setEnabledByDefault(true);
+ spec->setEnabledBySettings(true);
}
if (!spec->isEnabledByDefault() && forceEnabledPlugins.contains(spec->name()))
- spec->d->setEnabledBySettings(true);
+ spec->setEnabledBySettings(true);
if (spec->isEnabledByDefault() && disabledPlugins.contains(spec->name()))
- spec->d->setEnabledBySettings(false);
+ spec->setEnabledBySettings(false);
pluginCategories[spec->category()].append(spec);
}
@@ -1803,21 +1781,49 @@ void PluginManagerPrivate::readPluginPaths()
emit q->pluginsChanged();
}
+/*!
+ \internal
+*/
+void PluginManagerPrivate::readPluginPaths()
+{
+ QVector newSpecs;
+
+ // from the file system
+ for (const QString &pluginFile : pluginFiles(pluginPaths)) {
+ expected_str spec = PluginSpecImpl::read(pluginFile);
+ if (!spec) {
+ qCWarning(pluginLog).noquote()
+ << QString("Ignoring plugin \"%1\" because: %2").arg(pluginFile).arg(spec.error());
+ continue;
+ }
+ newSpecs.append(*spec);
+ }
+
+ // static
+ for (const QStaticPlugin &plugin : QPluginLoader::staticPlugins()) {
+ expected_str spec = PluginSpecImpl::read(plugin);
+ QTC_ASSERT_EXPECTED(spec, continue);
+ newSpecs.append(*spec);
+ }
+
+ addPlugins(newSpecs);
+}
+
void PluginManagerPrivate::resolveDependencies()
{
for (PluginSpec *spec : std::as_const(pluginSpecs))
- spec->d->resolveDependencies(pluginSpecs);
+ spec->resolveDependencies(pluginSpecs);
}
void PluginManagerPrivate::enableDependenciesIndirectly()
{
for (PluginSpec *spec : std::as_const(pluginSpecs))
- spec->d->enabledIndirectly = false;
+ spec->setEnabledIndirectly(false);
// cannot use reverse loadQueue here, because test dependencies can introduce circles
QVector queue = Utils::filtered(pluginSpecs, &PluginSpec::isEffectivelyEnabled);
while (!queue.isEmpty()) {
PluginSpec *spec = queue.takeFirst();
- queue += spec->d->enableDependenciesIndirectly(containsTestSpec(spec));
+ queue += spec->enableDependenciesIndirectly(containsTestSpec(spec));
}
}
diff --git a/src/libs/extensionsystem/pluginmanager.h b/src/libs/extensionsystem/pluginmanager.h
index a38f3c3fe7b..74237db5b34 100644
--- a/src/libs/extensionsystem/pluginmanager.h
+++ b/src/libs/extensionsystem/pluginmanager.h
@@ -82,6 +82,8 @@ public:
static void checkForProblematicPlugins();
static PluginSpec *specForPlugin(IPlugin *plugin);
+ static void addPlugins(const QVector &specs);
+
// Settings
static void setSettings(Utils::QtcSettings *settings);
static Utils::QtcSettings *settings();
diff --git a/src/libs/extensionsystem/pluginmanager_p.h b/src/libs/extensionsystem/pluginmanager_p.h
index 27efbf4c8f3..2404a8b49e9 100644
--- a/src/libs/extensionsystem/pluginmanager_p.h
+++ b/src/libs/extensionsystem/pluginmanager_p.h
@@ -36,8 +36,6 @@ class PluginManager;
namespace Internal {
-class PluginSpecPrivate;
-
class EXTENSIONSYSTEM_TEST_EXPORT PluginManagerPrivate : public QObject
{
public:
@@ -52,6 +50,8 @@ public:
void checkForProblematicPlugins();
void loadPlugins();
void loadPluginsAtRuntime(const QSet &plugins);
+ void addPlugins(const QVector &specs);
+
void shutdown();
void setPluginPaths(const QStringList &paths);
const QVector loadQueue();
@@ -119,10 +119,6 @@ public:
PluginSpec *pluginForOption(const QString &option, bool *requiresArgument) const;
PluginSpec *pluginByName(const QString &name) const;
- // used by tests
- static PluginSpec *createSpec();
- static PluginSpecPrivate *privateSpec(PluginSpec *spec);
-
static void addTestCreator(IPlugin *plugin, const std::function &testCreator);
mutable QReadWriteLock m_lock;
diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp
index 49f9c680fe8..8740854e7e5 100644
--- a/src/libs/extensionsystem/pluginspec.cpp
+++ b/src/libs/extensionsystem/pluginspec.cpp
@@ -6,7 +6,6 @@
#include "extensionsystemtr.h"
#include "iplugin.h"
#include "pluginmanager.h"
-#include "pluginspec_p.h"
#include
#include
@@ -25,6 +24,7 @@
#include
using namespace ExtensionSystem::Internal;
+using namespace Utils;
namespace ExtensionSystem {
@@ -168,22 +168,78 @@ QString PluginDependency::toString() const
return name + " (" + version + typeString(type) + ")";
}
-/*!
- \internal
-*/
-PluginSpec::PluginSpec()
- : d(new PluginSpecPrivate(this))
+namespace Internal {
+class PluginSpecImplPrivate
{
-}
+public:
+ std::optional loader;
+ std::optional staticPlugin;
+
+ IPlugin *plugin;
+};
+
+class PluginSpecPrivate
+{
+public:
+ ExtensionSystem::PerformanceData performanceData;
+
+ QString name;
+ QString version;
+ QString compatVersion;
+ QString vendor;
+ QString category;
+ QString description;
+ QString longDescription;
+ QString url;
+ QString license;
+ QString revision;
+ QString copyright;
+ QStringList arguments;
+ QRegularExpression platformSpecification;
+ QVector dependencies;
+
+ PluginSpecImpl::PluginArgumentDescriptions argumentDescriptions;
+ QString location;
+ QString filePath;
+
+ bool experimental{false};
+ bool deprecated{false};
+ bool required{false};
+
+ bool enabledByDefault{false};
+ bool enabledBySettings{true};
+ bool enabledIndirectly{false};
+ bool forceEnabled{false};
+ bool forceDisabled{false};
+ bool softLoadable{false};
+
+ std::optional errorString;
+
+ PluginSpec::State state;
+ QHash dependencySpecs;
+
+ QJsonObject metaData;
+
+ Utils::expected_str readMetaData(const QJsonObject &metaData);
+ Utils::expected_str reportError(const QString &error)
+ {
+ errorString = error;
+ return {};
+ };
+};
+} // namespace Internal
/*!
\internal
*/
-PluginSpec::~PluginSpec()
-{
- delete d;
- d = nullptr;
-}
+PluginSpecImpl::PluginSpecImpl()
+ : d(new PluginSpecImplPrivate)
+{}
+
+/*!
+ \internal
+*/
+PluginSpecImpl::~PluginSpecImpl() = default;
/*!
Returns the plugin name. This is valid after the PluginSpec::Read state is
@@ -278,10 +334,7 @@ QString PluginSpec::category() const
QString PluginSpec::revision() const
{
- const QJsonValue revision = metaData().value("Revision");
- if (revision.isString())
- return revision.toString();
- return QString();
+ return d->revision;
}
/*!
@@ -419,7 +472,7 @@ QJsonObject PluginSpec::metaData() const
return d->metaData;
}
-const PerformanceData &PluginSpec::performanceData() const
+PerformanceData &PluginSpec::performanceData() const
{
return d->performanceData;
}
@@ -491,7 +544,7 @@ PluginSpec::State PluginSpec::state() const
*/
bool PluginSpec::hasError() const
{
- return d->hasError;
+ return d->errorString.has_value();
}
/*!
@@ -500,7 +553,7 @@ bool PluginSpec::hasError() const
*/
QString PluginSpec::errorString() const
{
- return d->errorString;
+ return d->errorString.value_or(QString());
}
/*!
@@ -509,9 +562,13 @@ QString PluginSpec::errorString() const
\sa PluginSpec::dependencies()
*/
-bool PluginSpec::provides(const QString &pluginName, const QString &version) const
+bool PluginSpec::provides(const QString &pluginName, const QString &pluginVersion) const
{
- return d->provides(pluginName, version);
+ if (QString::compare(pluginName, name(), Qt::CaseInsensitive) != 0)
+ return false;
+
+ return (versionCompare(version(), pluginVersion) >= 0)
+ && (versionCompare(compatVersion(), pluginVersion) <= 0);
}
/*!
@@ -519,7 +576,7 @@ bool PluginSpec::provides(const QString &pluginName, const QString &version) con
already been successfully loaded. That is, the PluginSpec::Loaded state
is reached.
*/
-IPlugin *PluginSpec::plugin() const
+IPlugin *PluginSpecImpl::plugin() const
{
return d->plugin;
}
@@ -548,6 +605,11 @@ bool PluginSpec::requiresAny(const QSet &plugins) const
return false;
}
+void PluginSpec::setEnabledByDefault(bool value)
+{
+ d->enabledByDefault = value;
+}
+
/*!
Sets whether the plugin should be loaded at startup to \a value.
@@ -555,27 +617,40 @@ bool PluginSpec::requiresAny(const QSet &plugins) const
*/
void PluginSpec::setEnabledBySettings(bool value)
{
- d->setEnabledBySettings(value);
+ d->enabledBySettings = value;
+}
+void PluginSpec::setEnabledIndirectly(bool value)
+{
+ d->enabledIndirectly = value;
+}
+void PluginSpec::setForceDisabled(bool value)
+{
+ d->forceDisabled = value;
+}
+void PluginSpec::setForceEnabled(bool value)
+{
+ d->forceEnabled = value;
}
-PluginSpec *PluginSpec::read(const QString &filePath)
+// returns the plugins that it actually indirectly enabled
+QVector PluginSpec::enableDependenciesIndirectly(bool enableTestDependencies)
{
- auto spec = new PluginSpec;
- if (!spec->d->read(filePath)) { // not a Qt Creator plugin
- delete spec;
- return nullptr;
- }
- return spec;
-}
+ if (!isEffectivelyEnabled()) // plugin not enabled, nothing to do
+ return {};
-PluginSpec *PluginSpec::read(const QStaticPlugin &plugin)
-{
- auto spec = new PluginSpec;
- if (!spec->d->read(plugin)) { // not a Qt Creator plugin
- delete spec;
- return nullptr;
+ QVector enabled;
+ for (auto it = d->dependencySpecs.cbegin(), end = d->dependencySpecs.cend(); it != end; ++it) {
+ if (it.key().type != PluginDependency::Required
+ && (!enableTestDependencies || it.key().type != PluginDependency::Test))
+ continue;
+
+ PluginSpec *dependencySpec = it.value();
+ if (!dependencySpec->isEffectivelyEnabled()) {
+ dependencySpec->setEnabledIndirectly(true);
+ enabled << dependencySpec;
+ }
}
- return spec;
+ return enabled;
}
//==========PluginSpecPrivate==================
@@ -610,112 +685,45 @@ namespace {
const char ARGUMENT_PARAMETER[] = "Parameter";
const char ARGUMENT_DESCRIPTION[] = "Description";
}
-/*!
- \internal
-*/
-PluginSpecPrivate::PluginSpecPrivate(PluginSpec *spec)
- : q(spec)
-{}
-
-void PluginSpecPrivate::reset()
-{
- name.clear();
- version.clear();
- compatVersion.clear();
- vendor.clear();
- copyright.clear();
- license.clear();
- description.clear();
- longDescription.clear();
- url.clear();
- category.clear();
- location.clear();
- filePath.clear();
- state = PluginSpec::Invalid;
- hasError = false;
- errorString.clear();
- dependencies.clear();
- metaData = QJsonObject();
- loader.reset();
- staticPlugin.reset();
-}
/*!
\internal
Returns false if the file does not represent a Qt Creator plugin.
*/
-bool PluginSpecPrivate::read(const QString &fileName)
+expected_str PluginSpecImpl::read(const QString &fileName)
{
- qCDebug(pluginLog) << "\nReading meta data of" << fileName;
- reset();
+ auto spec = new PluginSpecImpl;
+
QFileInfo fileInfo(fileName);
- location = fileInfo.absolutePath();
- filePath = fileInfo.absoluteFilePath();
- loader.emplace();
+ spec->setLocation(fileInfo.absolutePath());
+ spec->setFilePath(fileInfo.absoluteFilePath());
+ spec->d->loader.emplace();
+
if (Utils::HostOsInfo::isMacHost())
- loader->setLoadHints(QLibrary::ExportExternalSymbolsHint);
- loader->setFileName(filePath);
- if (loader->fileName().isEmpty()) {
- qCDebug(pluginLog) << "Cannot open file";
- return false;
- }
+ spec->d->loader->setLoadHints(QLibrary::ExportExternalSymbolsHint);
- if (!readMetaData(loader->metaData()))
- return false;
+ spec->d->loader->setFileName(fileInfo.absoluteFilePath());
+ if (spec->d->loader->fileName().isEmpty())
+ return make_unexpected(::ExtensionSystem::Tr::tr("Cannot open file"));
- state = PluginSpec::Read;
- return true;
+ expected_str r = spec->readMetaData(spec->d->loader->metaData());
+ if (!r)
+ return make_unexpected(r.error());
+
+ return spec;
}
-bool PluginSpecPrivate::read(const QStaticPlugin &plugin)
+expected_str PluginSpecImpl::read(const QStaticPlugin &plugin)
{
+ auto spec = new PluginSpecImpl;
+
qCDebug(pluginLog) << "\nReading meta data of static plugin";
- reset();
- staticPlugin = plugin;
- if (!readMetaData(plugin.metaData()))
- return false;
+ spec->d->staticPlugin = plugin;
+ expected_str r = spec->readMetaData(plugin.metaData());
+ if (!r)
+ return make_unexpected(r.error());
- state = PluginSpec::Read;
- return true;
-}
-
-void PluginSpecPrivate::setEnabledBySettings(bool value)
-{
- enabledBySettings = value;
-}
-
-void PluginSpecPrivate::setEnabledByDefault(bool value)
-{
- enabledByDefault = value;
-}
-
-void PluginSpecPrivate::setForceEnabled(bool value)
-{
- forceEnabled = value;
- if (value)
- forceDisabled = false;
-}
-
-void PluginSpecPrivate::setForceDisabled(bool value)
-{
- if (value)
- forceEnabled = false;
- forceDisabled = value;
-}
-
-void PluginSpecPrivate::setSoftLoadable(bool value)
-{
- softLoadable = value;
-}
-
-/*!
- \internal
-*/
-bool PluginSpecPrivate::reportError(const QString &err)
-{
- errorString = err;
- hasError = true;
- return true;
+ return spec;
}
static inline QString msgValueMissing(const char *key)
@@ -725,58 +733,67 @@ static inline QString msgValueMissing(const char *key)
static inline QString msgValueIsNotAString(const char *key)
{
- return Tr::tr("Value for key \"%1\" is not a string")
- .arg(QLatin1String(key));
+ return Tr::tr("Value for key \"%1\" is not a string").arg(QLatin1String(key));
}
static inline QString msgValueIsNotABool(const char *key)
{
- return Tr::tr("Value for key \"%1\" is not a bool")
- .arg(QLatin1String(key));
+ return Tr::tr("Value for key \"%1\" is not a bool").arg(QLatin1String(key));
}
static inline QString msgValueIsNotAObjectArray(const char *key)
{
- return Tr::tr("Value for key \"%1\" is not an array of objects")
- .arg(QLatin1String(key));
+ return Tr::tr("Value for key \"%1\" is not an array of objects").arg(QLatin1String(key));
}
static inline QString msgValueIsNotAMultilineString(const char *key)
{
return Tr::tr("Value for key \"%1\" is not a string and not an array of strings")
- .arg(QLatin1String(key));
+ .arg(QLatin1String(key));
}
static inline QString msgInvalidFormat(const char *key, const QString &content)
{
- return Tr::tr("Value \"%2\" for key \"%1\" has invalid format")
- .arg(QLatin1String(key), content);
+ return Tr::tr("Value \"%2\" for key \"%1\" has invalid format").arg(QLatin1String(key), content);
+}
+
+Utils::expected_str PluginSpec::readMetaData(const QJsonObject &metaData)
+{
+ return d->readMetaData(metaData);
+}
+Utils::expected_str PluginSpec::reportError(const QString &error)
+{
+ return d->reportError(error);
}
/*!
\internal
*/
-bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
+expected_str PluginSpecImpl::readMetaData(const QJsonObject &pluginMetaData)
{
- qCDebug(pluginLog) << "MetaData:" << QJsonDocument(pluginMetaData).toJson();
+ qCDebug(pluginLog).noquote() << "MetaData:" << QJsonDocument(pluginMetaData).toJson();
QJsonValue value;
value = pluginMetaData.value(QLatin1String("IID"));
- if (!value.isString()) {
- qCDebug(pluginLog) << "Not a plugin (no string IID found)";
- return false;
- }
- if (value.toString() != PluginManager::pluginIID()) {
- qCDebug(pluginLog) << "Plugin ignored (IID does not match)";
- return false;
- }
+ if (!value.isString())
+ return make_unexpected(::ExtensionSystem::Tr::tr("No IID found"));
+
+ if (value.toString() != PluginManager::pluginIID())
+ return make_unexpected(::ExtensionSystem::Tr::tr("Expected IID \"%1\", but found \"%2\"")
+ .arg(PluginManager::pluginIID())
+ .arg(value.toString()));
value = pluginMetaData.value(QLatin1String(PLUGIN_METADATA));
- if (!value.isObject()) {
+ if (!value.isObject())
return reportError(::ExtensionSystem::Tr::tr("Plugin meta data not found"));
- }
- metaData = value.toObject();
- value = metaData.value(QLatin1String(PLUGIN_NAME));
+ return PluginSpec::readMetaData(value.toObject());
+}
+
+Utils::expected_str PluginSpecPrivate::readMetaData(const QJsonObject &data)
+{
+ metaData = data;
+
+ QJsonValue value = metaData.value(QLatin1String(PLUGIN_NAME));
if (value.isUndefined())
return reportError(msgValueMissing(PLUGIN_NAME));
if (!value.isString())
@@ -789,14 +806,14 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
if (!value.isString())
return reportError(msgValueIsNotAString(PLUGIN_VERSION));
version = value.toString();
- if (!isValidVersion(version))
+ if (!PluginSpec::isValidVersion(version))
return reportError(msgInvalidFormat(PLUGIN_VERSION, version));
value = metaData.value(QLatin1String(PLUGIN_COMPATVERSION));
if (!value.isUndefined() && !value.isString())
return reportError(msgValueIsNotAString(PLUGIN_COMPATVERSION));
compatVersion = value.toString(version);
- if (!value.isUndefined() && !isValidVersion(compatVersion))
+ if (!value.isUndefined() && !PluginSpec::isValidVersion(compatVersion))
return reportError(msgInvalidFormat(PLUGIN_COMPATVERSION, compatVersion));
value = metaData.value(QLatin1String(PLUGIN_REQUIRED));
@@ -844,11 +861,11 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
copyright = value.toString();
value = metaData.value(QLatin1String(DESCRIPTION));
- if (!value.isUndefined() && !Utils::readMultiLineString(value, &description))
+ if (!value.isUndefined() && !readMultiLineString(value, &description))
return reportError(msgValueIsNotAString(DESCRIPTION));
value = metaData.value(QLatin1String(LONGDESCRIPTION));
- if (!value.isUndefined() && !Utils::readMultiLineString(value, &longDescription))
+ if (!value.isUndefined() && !readMultiLineString(value, &longDescription))
return reportError(msgValueIsNotAString(LONGDESCRIPTION));
value = metaData.value(QLatin1String(URL));
@@ -862,9 +879,14 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
category = value.toString();
value = metaData.value(QLatin1String(LICENSE));
- if (!value.isUndefined() && !Utils::readMultiLineString(value, &license))
+ if (!value.isUndefined() && !readMultiLineString(value, &license))
return reportError(msgValueIsNotAMultilineString(LICENSE));
+ value = metaData.value("Revision");
+ if (!value.isUndefined() && !value.isString())
+ return reportError(msgValueIsNotAString("Revision"));
+ revision = value.toString();
+
value = metaData.value(QLatin1String(PLATFORM));
if (!value.isUndefined() && !value.isString())
return reportError(msgValueIsNotAString(PLATFORM));
@@ -906,7 +928,7 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
.arg(msgValueIsNotAString(DEPENDENCY_VERSION)));
}
dep.version = value.toString();
- if (!isValidVersion(dep.version)) {
+ if (!PluginSpec::isValidVersion(dep.version)) {
return reportError(
::ExtensionSystem::Tr::tr("Dependency: %1")
.arg(msgInvalidFormat(DEPENDENCY_VERSION, dep.version)));
@@ -987,23 +1009,15 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData)
}
}
- return true;
+ state = PluginSpecImpl::Read;
+
+ return {};
}
/*!
\internal
*/
-bool PluginSpecPrivate::provides(const QString &pluginName, const QString &pluginVersion) const
-{
- if (QString::compare(pluginName, name, Qt::CaseInsensitive) != 0)
- return false;
- return (versionCompare(version, pluginVersion) >= 0) && (versionCompare(compatVersion, pluginVersion) <= 0);
-}
-
-/*!
- \internal
-*/
-const QRegularExpression &PluginSpecPrivate::versionRegExp()
+static const QRegularExpression &versionRegExp()
{
static const QRegularExpression reg("^([0-9]+)(?:[.]([0-9]+))?(?:[.]([0-9]+))?(?:_([0-9]+))?$");
return reg;
@@ -1011,7 +1025,7 @@ const QRegularExpression &PluginSpecPrivate::versionRegExp()
/*!
\internal
*/
-bool PluginSpecPrivate::isValidVersion(const QString &version)
+bool PluginSpec::isValidVersion(const QString &version)
{
return versionRegExp().match(version).hasMatch();
}
@@ -1019,7 +1033,7 @@ bool PluginSpecPrivate::isValidVersion(const QString &version)
/*!
\internal
*/
-int PluginSpecPrivate::versionCompare(const QString &version1, const QString &version2)
+int PluginSpec::versionCompare(const QString &version1, const QString &version2)
{
const QRegularExpressionMatch match1 = versionRegExp().match(version1);
const QRegularExpressionMatch match2 = versionRegExp().match(version2);
@@ -1041,196 +1055,205 @@ int PluginSpecPrivate::versionCompare(const QString &version1, const QString &ve
/*!
\internal
*/
-bool PluginSpecPrivate::resolveDependencies(const QVector &specs)
+bool PluginSpec::resolveDependencies(const QVector &specs)
{
- if (hasError)
+ if (hasError())
return false;
- if (state == PluginSpec::Resolved)
- state = PluginSpec::Read; // Go back, so we just re-resolve the dependencies.
- if (state != PluginSpec::Read) {
- errorString = ::ExtensionSystem::Tr::tr("Resolving dependencies failed because state != Read");
- hasError = true;
+ if (state() > PluginSpecImpl::Resolved)
+ return true; // We are resolved already.
+ if (state() == PluginSpecImpl::Resolved)
+ setState(PluginSpecImpl::Read); // Go back, so we just re-resolve the dependencies.
+ if (state() != PluginSpecImpl::Read) {
+ setError(::ExtensionSystem::Tr::tr("Resolving dependencies failed because state != Read"));
return false;
}
+
QHash resolvedDependencies;
- for (const PluginDependency &dependency : std::as_const(dependencies)) {
- PluginSpec * const found = Utils::findOrDefault(specs, [&dependency](PluginSpec *spec) {
+ for (const PluginDependency &dependency : d->dependencies) {
+ PluginSpec *const found = findOrDefault(specs, [&dependency](PluginSpec *spec) {
return spec->provides(dependency.name, dependency.version);
});
if (!found) {
if (dependency.type == PluginDependency::Required) {
- hasError = true;
- if (!errorString.isEmpty())
- errorString.append(QLatin1Char('\n'));
- errorString.append(::ExtensionSystem::Tr::tr("Could not resolve dependency '%1(%2)'")
- .arg(dependency.name, dependency.version));
+ const QString error = ::ExtensionSystem::Tr::tr(
+ "Could not resolve dependency '%1(%2)'")
+ .arg(dependency.name, dependency.version);
+ if (hasError())
+ setError(errorString() + '\n' + error);
+ else
+ setError(error);
}
continue;
}
resolvedDependencies.insert(dependency, found);
}
- if (hasError)
+ if (hasError())
return false;
- dependencySpecs = resolvedDependencies;
+ d->dependencySpecs = resolvedDependencies;
- state = PluginSpec::Resolved;
+ d->state = PluginSpecImpl::Resolved;
return true;
}
-// returns the plugins that it actually indirectly enabled
-QVector PluginSpecPrivate::enableDependenciesIndirectly(bool enableTestDependencies)
+PluginSpec::PluginSpec()
+ : d(new PluginSpecPrivate())
+{}
+
+PluginSpec::~PluginSpec() = default;
+
+void PluginSpec::setState(State state)
{
- if (!q->isEffectivelyEnabled()) // plugin not enabled, nothing to do
- return {};
- QVector enabled;
- for (auto it = dependencySpecs.cbegin(), end = dependencySpecs.cend(); it != end; ++it) {
- if (it.key().type != PluginDependency::Required
- && (!enableTestDependencies || it.key().type != PluginDependency::Test))
- continue;
- PluginSpec *dependencySpec = it.value();
- if (!dependencySpec->isEffectivelyEnabled()) {
- dependencySpec->d->enabledIndirectly = true;
- enabled << dependencySpec;
- }
- }
- return enabled;
+ d->state = state;
+}
+
+void PluginSpec::setLocation(const QString &location)
+{
+ d->location = location;
+}
+
+void PluginSpec::setFilePath(const QString &filePath)
+{
+ d->filePath = filePath;
+}
+
+void PluginSpec::setError(const QString &errorString)
+{
+ d->errorString = errorString;
}
/*!
\internal
*/
-bool PluginSpecPrivate::loadLibrary()
+bool PluginSpecImpl::loadLibrary()
{
- if (hasError)
+ if (hasError())
return false;
- if (state != PluginSpec::Resolved) {
- if (state == PluginSpec::Loaded)
+
+ if (state() != PluginSpecImpl::Resolved) {
+ if (state() == PluginSpecImpl::Loaded)
return true;
- errorString =
- ::ExtensionSystem::Tr::tr("Loading the library failed because state != Resolved");
- hasError = true;
+ setError(::ExtensionSystem::Tr::tr("Loading the library failed because state != Resolved"));
return false;
}
- if (loader && !loader->load()) {
- hasError = true;
- errorString = QDir::toNativeSeparators(filePath) + QString::fromLatin1(": ")
- + loader->errorString();
+ if (d->loader && !d->loader->load()) {
+ setError(QDir::toNativeSeparators(filePath()) + QString::fromLatin1(": ")
+ + d->loader->errorString());
return false;
}
- auto *pluginObject = loader ? qobject_cast(loader->instance())
- : qobject_cast(staticPlugin->instance());
+ auto *pluginObject = d->loader ? qobject_cast(d->loader->instance())
+ : qobject_cast(d->staticPlugin->instance());
if (!pluginObject) {
- hasError = true;
- errorString =
- ::ExtensionSystem::Tr::tr("Plugin is not valid (does not derive from IPlugin)");
- if (loader)
- loader->unload();
+ setError(::ExtensionSystem::Tr::tr("Plugin is not valid (does not derive from IPlugin)"));
+ if (d->loader)
+ d->loader->unload();
return false;
}
- state = PluginSpec::Loaded;
- plugin = pluginObject;
+ setState(PluginSpecImpl::Loaded);
+ d->plugin = pluginObject;
return true;
}
/*!
\internal
*/
-bool PluginSpecPrivate::initializePlugin()
+bool PluginSpecImpl::initializePlugin()
{
- if (hasError)
+ if (hasError())
return false;
- if (state != PluginSpec::Loaded) {
- if (state == PluginSpec::Initialized)
+
+ if (state() != PluginSpecImpl::Loaded) {
+ if (state() == PluginSpecImpl::Initialized)
return true;
- errorString = ::ExtensionSystem::Tr::tr(
- "Initializing the plugin failed because state != Loaded");
- hasError = true;
+ setError(
+ ::ExtensionSystem::Tr::tr("Initializing the plugin failed because state != Loaded"));
return false;
}
- if (!plugin) {
- errorString = ::ExtensionSystem::Tr::tr(
- "Internal error: have no plugin instance to initialize");
- hasError = true;
+ if (!d->plugin) {
+ setError(
+ ::ExtensionSystem::Tr::tr("Internal error: have no plugin instance to initialize"));
return false;
}
QString err;
- if (!plugin->initialize(arguments, &err)) {
- errorString = ::ExtensionSystem::Tr::tr("Plugin initialization failed: %1").arg(err);
- hasError = true;
+ if (!d->plugin->initialize(arguments(), &err)) {
+ setError(::ExtensionSystem::Tr::tr("Plugin initialization failed: %1").arg(err));
return false;
}
- state = PluginSpec::Initialized;
+ setState(PluginSpecImpl::Initialized);
return true;
}
/*!
\internal
*/
-bool PluginSpecPrivate::initializeExtensions()
+bool PluginSpecImpl::initializeExtensions()
{
- if (hasError)
+ if (hasError())
return false;
- if (state != PluginSpec::Initialized) {
- if (state == PluginSpec::Running)
+
+ if (state() != PluginSpecImpl::Initialized) {
+ if (state() == PluginSpecImpl::Running)
return true;
- errorString = ::ExtensionSystem::Tr::tr(
- "Cannot perform extensionsInitialized because state != Initialized");
- hasError = true;
+ setError(::ExtensionSystem::Tr::tr(
+ "Cannot perform extensionsInitialized because state != Initialized"));
return false;
}
- if (!plugin) {
- errorString = ::ExtensionSystem::Tr::tr(
- "Internal error: have no plugin instance to perform extensionsInitialized");
- hasError = true;
+ if (!d->plugin) {
+ setError(::ExtensionSystem::Tr::tr(
+ "Internal error: have no plugin instance to perform extensionsInitialized"));
return false;
}
- plugin->extensionsInitialized();
- state = PluginSpec::Running;
+ d->plugin->extensionsInitialized();
+ setState(PluginSpecImpl::Running);
return true;
}
/*!
\internal
*/
-bool PluginSpecPrivate::delayedInitialize()
+bool PluginSpecImpl::delayedInitialize()
{
- if (hasError)
+ if (hasError())
+ return true;
+
+ if (state() != PluginSpecImpl::Running)
return false;
- if (state != PluginSpec::Running)
- return false;
- if (!plugin) {
- errorString = ::ExtensionSystem::Tr::tr(
- "Internal error: have no plugin instance to perform delayedInitialize");
- hasError = true;
+ if (!d->plugin) {
+ setError(::ExtensionSystem::Tr::tr(
+ "Internal error: have no plugin instance to perform delayedInitialize"));
return false;
}
- const bool res = plugin->delayedInitialize();
+ const bool res = d->plugin->delayedInitialize();
return res;
}
/*!
\internal
*/
-IPlugin::ShutdownFlag PluginSpecPrivate::stop()
+IPlugin::ShutdownFlag PluginSpecImpl::stop()
{
- if (!plugin)
+ if (hasError())
+ return IPlugin::ShutdownFlag::SynchronousShutdown;
+
+ if (!d->plugin)
return IPlugin::SynchronousShutdown;
- state = PluginSpec::Stopped;
- return plugin->aboutToShutdown();
+ setState(PluginSpecImpl::Stopped);
+ return d->plugin->aboutToShutdown();
}
/*!
\internal
*/
-void PluginSpecPrivate::kill()
+void PluginSpecImpl::kill()
{
- if (!plugin)
+ if (hasError())
return;
- delete plugin;
- plugin = nullptr;
- state = PluginSpec::Deleted;
-}
-} // ExtensionSystem
+ if (!d->plugin)
+ return;
+ delete d->plugin;
+ d->plugin = nullptr;
+ setState(PluginSpecImpl::Deleted);
+}
+} // namespace ExtensionSystem
diff --git a/src/libs/extensionsystem/pluginspec.h b/src/libs/extensionsystem/pluginspec.h
index 8db6bb44114..09b8f55618f 100644
--- a/src/libs/extensionsystem/pluginspec.h
+++ b/src/libs/extensionsystem/pluginspec.h
@@ -5,6 +5,10 @@
#include "extensionsystem_global.h"
+#include "iplugin.h"
+
+#include
+
#include
#include
#include
@@ -14,17 +18,19 @@ QT_BEGIN_NAMESPACE
class QRegularExpression;
QT_END_NAMESPACE
+class tst_PluginSpec;
+
namespace ExtensionSystem {
namespace Internal {
class OptionsParser;
-class PluginSpecPrivate;
+class PluginSpecImplPrivate;
class PluginManagerPrivate;
+class PluginSpecPrivate;
} // Internal
-class IPlugin;
class PluginView;
struct EXTENSIONSYSTEM_EXPORT PluginDependency
@@ -37,8 +43,6 @@ struct EXTENSIONSYSTEM_EXPORT PluginDependency
PluginDependency() : type(Required) {}
- friend size_t qHash(const PluginDependency &value);
-
QString name;
QString version;
Type type;
@@ -46,6 +50,8 @@ struct EXTENSIONSYSTEM_EXPORT PluginDependency
QString toString() const;
};
+size_t EXTENSIONSYSTEM_EXPORT qHash(const PluginDependency &value);
+
struct EXTENSIONSYSTEM_EXPORT PluginArgumentDescription
{
QString name;
@@ -73,77 +79,126 @@ struct EXTENSIONSYSTEM_EXPORT PerformanceData
class EXTENSIONSYSTEM_EXPORT PluginSpec
{
+ friend class ::tst_PluginSpec;
+ friend class Internal::PluginManagerPrivate;
+ friend class Internal::OptionsParser;
+
public:
- enum State { Invalid, Read, Resolved, Loaded, Initialized, Running, Stopped, Deleted};
-
- ~PluginSpec();
-
- // information from the xml file, valid after 'Read' state is reached
- QString name() const;
- QString version() const;
- QString compatVersion() const;
- QString vendor() const;
- QString copyright() const;
- QString license() const;
- QString description() const;
- QString longDescription() const;
- QString url() const;
- QString category() const;
- QString revision() const;
- QRegularExpression platformSpecification() const;
- bool isAvailableForHostPlatform() const;
- bool isRequired() const;
- bool isExperimental() const;
- bool isDeprecated() const;
- bool isEnabledByDefault() const;
- bool isEnabledBySettings() const;
- bool isEffectivelyEnabled() const;
- bool isEnabledIndirectly() const;
- bool isForceEnabled() const;
- bool isForceDisabled() const;
- bool isSoftLoadable() const;
- QVector dependencies() const;
- QJsonObject metaData() const;
- const PerformanceData &performanceData() const;
+ PluginSpec();
+ virtual ~PluginSpec();
using PluginArgumentDescriptions = QVector;
- PluginArgumentDescriptions argumentDescriptions() const;
+ enum State { Invalid, Read, Resolved, Loaded, Initialized, Running, Stopped, Deleted};
- // other information, valid after 'Read' state is reached
- QString location() const;
- QString filePath() const;
+ // information read from the plugin, valid after 'Read' state is reached
+ virtual QString name() const;
+ virtual QString version() const;
+ virtual QString compatVersion() const;
+ virtual QString vendor() const;
+ virtual QString copyright() const;
+ virtual QString license() const;
+ virtual QString description() const;
+ virtual QString longDescription() const;
+ virtual QString url() const;
+ virtual QString category() const;
+ virtual QString revision() const;
+ virtual QRegularExpression platformSpecification() const;
- QStringList arguments() const;
- void setArguments(const QStringList &arguments);
- void addArgument(const QString &argument);
+ virtual bool isAvailableForHostPlatform() const;
+ virtual bool isRequired() const;
+ virtual bool isExperimental() const;
+ virtual bool isDeprecated() const;
+ virtual bool isEnabledByDefault() const;
+ virtual bool isEnabledBySettings() const;
+ virtual bool isEffectivelyEnabled() const;
+ virtual bool isEnabledIndirectly() const;
+ virtual bool isForceEnabled() const;
+ virtual bool isForceDisabled() const;
+ virtual bool isSoftLoadable() const;
- bool provides(const QString &pluginName, const QString &version) const;
+ virtual QVector dependencies() const;
+ virtual QJsonObject metaData() const;
+ virtual PerformanceData &performanceData() const;
+ virtual PluginArgumentDescriptions argumentDescriptions() const;
+ virtual QString location() const;
+ virtual QString filePath() const;
+ virtual QStringList arguments() const;
+ virtual void setArguments(const QStringList &arguments);
+ virtual void addArgument(const QString &argument);
+ virtual QHash dependencySpecs() const;
- // dependency specs, valid after 'Resolved' state is reached
- QHash dependencySpecs() const;
- bool requiresAny(const QSet &plugins) const;
+ virtual bool provides(const QString &pluginName, const QString &pluginVersion) const;
+ virtual bool requiresAny(const QSet &plugins) const;
+ virtual QVector enableDependenciesIndirectly(bool enableTestDependencies);
+ virtual bool resolveDependencies(const QVector &pluginSpecs);
- // linked plugin instance, valid after 'Loaded' state is reached
- IPlugin *plugin() const;
+ virtual IPlugin *plugin() const = 0;
+ virtual State state() const;
+ virtual bool hasError() const;
+ virtual QString errorString() const;
- // state
- State state() const;
- bool hasError() const;
- QString errorString() const;
+ static bool isValidVersion(const QString &version);
+ static int versionCompare(const QString &version1, const QString &version2);
- void setEnabledBySettings(bool value);
+ virtual void setEnabledBySettings(bool value);
- static PluginSpec *read(const QString &filePath);
- static PluginSpec *read(const QStaticPlugin &plugin);
+protected:
+ virtual void setEnabledByDefault(bool value);
+ virtual void setEnabledIndirectly(bool value);
+ virtual void setForceDisabled(bool value);
+ virtual void setForceEnabled(bool value);
+
+ virtual bool loadLibrary() = 0;
+ virtual bool initializePlugin() = 0;
+ virtual bool initializeExtensions() = 0;
+ virtual bool delayedInitialize() = 0;
+ virtual IPlugin::ShutdownFlag stop() = 0;
+ virtual void kill() = 0;
+
+ virtual void setError(const QString &errorString);
+
+protected:
+ virtual void setState(State state);
+
+ virtual void setLocation(const QString &location);
+ virtual void setFilePath(const QString &filePath);
+ virtual Utils::expected_str readMetaData(const QJsonObject &metaData);
+ Utils::expected_str reportError(const QString &error);
private:
- PluginSpec();
+ std::unique_ptr d;
+};
- Internal::PluginSpecPrivate *d;
+class EXTENSIONSYSTEM_TEST_EXPORT PluginSpecImpl : public PluginSpec
+{
+public:
+ ~PluginSpecImpl() override;
+
+ // linked plugin instance, valid after 'Loaded' state is reached
+ IPlugin *plugin() const override;
+
+ bool loadLibrary() override;
+ bool initializePlugin() override;
+ bool initializeExtensions() override;
+ bool delayedInitialize() override;
+ IPlugin::ShutdownFlag stop() override;
+ void kill() override;
+
+ static Utils::expected_str read(const QString &filePath);
+ static Utils::expected_str read(const QStaticPlugin &plugin);
+
+ Utils::expected_str readMetaData(const QJsonObject &pluginMetaData) override;
+
+protected:
+ PluginSpecImpl();
+
+private:
+ std::unique_ptr d;
friend class PluginView;
friend class Internal::OptionsParser;
friend class Internal::PluginManagerPrivate;
- friend class Internal::PluginSpecPrivate;
+ friend class Internal::PluginSpecImplPrivate;
+ friend class ::tst_PluginSpec;
};
} // namespace ExtensionSystem
diff --git a/src/libs/extensionsystem/pluginspec_p.h b/src/libs/extensionsystem/pluginspec_p.h
deleted file mode 100644
index 61832213cad..00000000000
--- a/src/libs/extensionsystem/pluginspec_p.h
+++ /dev/null
@@ -1,107 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "pluginspec.h"
-#include "iplugin.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-namespace ExtensionSystem {
-
-class IPlugin;
-
-namespace Internal {
-
-class EXTENSIONSYSTEM_TEST_EXPORT PluginSpecPrivate : public QObject
-{
- Q_OBJECT
-
-public:
- PluginSpecPrivate(PluginSpec *spec);
-
- void reset();
- bool read(const QString &fileName);
- bool read(const QStaticPlugin &plugin);
- bool provides(const QString &pluginName, const QString &version) const;
- bool resolveDependencies(const QVector &specs);
- bool loadLibrary();
- bool initializePlugin();
- bool initializeExtensions();
- bool delayedInitialize();
- IPlugin::ShutdownFlag stop();
- void kill();
-
- void setEnabledBySettings(bool value);
- void setEnabledByDefault(bool value);
- void setForceEnabled(bool value);
- void setForceDisabled(bool value);
- void setSoftLoadable(bool value);
-
- std::optional loader;
- std::optional staticPlugin;
-
- QString name;
- QString version;
- QString compatVersion;
- bool required = false;
- bool experimental = false;
- bool enabledByDefault = true;
- bool deprecated = false;
- QString vendor;
- QString copyright;
- QString license;
- QString description;
- QString longDescription;
- QString url;
- QString category;
- QRegularExpression platformSpecification;
- QVector dependencies;
- QJsonObject metaData;
- bool enabledBySettings = true;
- bool enabledIndirectly = false;
- bool forceEnabled = false;
- bool forceDisabled = false;
- bool softLoadable = false;
-
- QString location;
- QString filePath;
- QStringList arguments;
-
- QHash dependencySpecs;
- PluginSpec::PluginArgumentDescriptions argumentDescriptions;
- IPlugin *plugin = nullptr;
-
- QList registeredPluginTests;
-
- PluginSpec::State state = PluginSpec::Invalid;
- bool hasError = false;
- QString errorString;
-
- PerformanceData performanceData;
-
- static bool isValidVersion(const QString &version);
- static int versionCompare(const QString &version1, const QString &version2);
-
- QVector enableDependenciesIndirectly(bool enableTestDependencies = false);
-
- bool readMetaData(const QJsonObject &pluginMetaData);
-
-private:
- PluginSpec *q;
-
- bool reportError(const QString &err);
- static const QRegularExpression &versionRegExp();
-};
-
-} // namespace Internal
-} // namespace ExtensionSystem
diff --git a/src/libs/extensionsystem/pluginview.cpp b/src/libs/extensionsystem/pluginview.cpp
index 40738be487f..07fa11c7a9a 100644
--- a/src/libs/extensionsystem/pluginview.cpp
+++ b/src/libs/extensionsystem/pluginview.cpp
@@ -5,7 +5,7 @@
#include "extensionsystemtr.h"
#include "pluginmanager.h"
-#include "pluginspec_p.h"
+#include "pluginspec.h"
#include
#include
@@ -416,8 +416,8 @@ bool PluginView::setPluginsEnabled(const QSet &plugins, bool enabl
});
QTC_ASSERT(item, continue);
if (m_affectedPlugins.find(spec) == m_affectedPlugins.end())
- m_affectedPlugins[spec] = spec->d->enabledBySettings;
- spec->d->setEnabledBySettings(enable);
+ m_affectedPlugins[spec] = spec->isEnabledBySettings();
+ spec->setEnabledBySettings(enable);
item->updateColumn(LoadedColumn);
item->parent()->updateColumn(LoadedColumn);
}
@@ -428,7 +428,7 @@ bool PluginView::setPluginsEnabled(const QSet &plugins, bool enabl
void PluginView::cancelChanges()
{
for (auto element : m_affectedPlugins)
- element.first->d->setEnabledBySettings(element.second);
+ element.first->setEnabledBySettings(element.second);
}
} // namespace ExtensionSystem
diff --git a/src/plugins/coreplugin/plugininstallwizard.cpp b/src/plugins/coreplugin/plugininstallwizard.cpp
index 5b342bf6c6a..55d77496744 100644
--- a/src/plugins/coreplugin/plugininstallwizard.cpp
+++ b/src/plugins/coreplugin/plugininstallwizard.cpp
@@ -154,11 +154,11 @@ void checkContents(QPromise &promise, const FilePath &tempDir)
if (promise.isCanceled())
return;
it.next();
- PluginSpec *spec = PluginSpec::read(it.filePath());
+ expected_str spec = PluginSpecImpl::read(it.filePath());
if (spec) {
// Is a Qt Creator plugin. Let's see if we find a Core dependency and check the
// version
- const QVector dependencies = spec->dependencies();
+ const QVector dependencies = (*spec)->dependencies();
const auto found = std::find_if(dependencies.constBegin(), dependencies.constEnd(),
[coreplugin](const PluginDependency &d) { return d.name == coreplugin->name(); });
if (found == dependencies.constEnd())
diff --git a/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong2.json b/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong2.json
index 2fd9df4d5d9..63a7fc5c551 100644
--- a/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong2.json
+++ b/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong2.json
@@ -11,6 +11,7 @@
"end of terms"
],
"Description" : [
+ "This spec is broken because no name is set.",
"This plugin is just a test.",
" it demonstrates the great use of the plugin spec."
],
diff --git a/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong3.json b/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong3.json
index 0b053f60140..7c43ef41d26 100644
--- a/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong3.json
+++ b/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong3.json
@@ -11,6 +11,7 @@
"end of terms"
],
"Description" : [
+ "This spec is wrong because no version is set.",
"This plugin is just a test.",
" it demonstrates the great use of the plugin spec."
],
diff --git a/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong4.json b/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong4.json
index c3a0d26922e..c8e1dd53d9f 100644
--- a/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong4.json
+++ b/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong4.json
@@ -12,6 +12,7 @@
"end of terms"
],
"Description" : [
+ "This spec is wrong because the first dependency has no name.",
"This plugin is just a test.",
" it demonstrates the great use of the plugin spec."
],
diff --git a/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong5.json b/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong5.json
index bdb095b3420..680ec4002ac 100644
--- a/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong5.json
+++ b/tests/auto/extensionsystem/pluginspec/testspecs/spec_wrong5.json
@@ -12,6 +12,7 @@
"end of terms"
],
"Description" : [
+ "This spec is wrong because the first dependencies version is invalid.",
"This plugin is just a test.",
" it demonstrates the great use of the plugin spec."
],
diff --git a/tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp b/tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp
index 762142b95ee..f919ef4139d 100644
--- a/tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp
+++ b/tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp
@@ -1,10 +1,9 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-#include
-#include
-#include
#include
+#include
+#include
#include
#include
@@ -85,109 +84,110 @@ void tst_PluginSpec::cleanupTestCase()
void tst_PluginSpec::read()
{
- Internal::PluginSpecPrivate spec(0);
- QCOMPARE(spec.state, PluginSpec::Invalid);
+ PluginSpecImpl spec;
+ QCOMPARE(spec.state(), PluginSpec::Invalid);
QVERIFY(spec.readMetaData(metaData("testspecs/spec1.json")));
- QVERIFY(!spec.hasError);
- QVERIFY(spec.errorString.isEmpty());
- QCOMPARE(spec.name, QString("test"));
- QCOMPARE(spec.version, QString("1.0.1"));
- QCOMPARE(spec.compatVersion, QString("1.0.0"));
- QCOMPARE(spec.required, false);
- QCOMPARE(spec.experimental, false);
- QCOMPARE(spec.enabledBySettings, true);
- QCOMPARE(spec.vendor, QString("The Qt Company Ltd"));
- QCOMPARE(spec.copyright, QString("(C) 2015 The Qt Company Ltd"));
- QCOMPARE(spec.license, QString("This is a default license bla\nblubbblubb\nend of terms"));
- QCOMPARE(spec.description, QString("This plugin is just a test."));
+ QVERIFY(!spec.hasError());
+ QVERIFY(spec.errorString().isEmpty());
+ QCOMPARE(spec.name(), QString("test"));
+ QCOMPARE(spec.version(), QString("1.0.1"));
+ QCOMPARE(spec.compatVersion(), QString("1.0.0"));
+ QCOMPARE(spec.isRequired(), false);
+ QCOMPARE(spec.isExperimental(), false);
+ QCOMPARE(spec.isEnabledBySettings(), true);
+ QCOMPARE(spec.vendor(), QString("The Qt Company Ltd"));
+ QCOMPARE(spec.copyright(), QString("(C) 2015 The Qt Company Ltd"));
+ QCOMPARE(spec.license(), QString("This is a default license bla\nblubbblubb\nend of terms"));
+ QCOMPARE(spec.description(), QString("This plugin is just a test."));
QCOMPARE(
- spec.longDescription,
+ spec.longDescription(),
QString(
"This plugin is just a test.\n it demonstrates the great use of the plugin spec."));
- QCOMPARE(spec.url, QString("http://www.qt.io"));
+ QCOMPARE(spec.url(), QString("http://www.qt.io"));
PluginDependency dep1;
dep1.name = QString("SomeOtherPlugin");
dep1.version = QString("2.3.0_2");
PluginDependency dep2;
dep2.name = QString("EvenOther");
dep2.version = QString("1.0.0");
- QCOMPARE(spec.dependencies, QVector() << dep1 << dep2);
+ QCOMPARE(spec.dependencies(), QVector() << dep1 << dep2);
// test missing compatVersion behavior
// and 'required' attribute
QVERIFY(spec.readMetaData(metaData("testspecs/spec2.json")));
- QCOMPARE(spec.version, QString("3.1.4_10"));
- QCOMPARE(spec.compatVersion, QString("3.1.4_10"));
- QCOMPARE(spec.required, true);
+ QCOMPARE(spec.version(), QString("3.1.4_10"));
+ QCOMPARE(spec.compatVersion(), QString("3.1.4_10"));
+ QCOMPARE(spec.isRequired(), true);
}
void tst_PluginSpec::readError()
{
- Internal::PluginSpecPrivate spec(0);
- QCOMPARE(spec.state, PluginSpec::Invalid);
+ PluginSpecImpl spec;
+ QCOMPARE(spec.state(), PluginSpec::Invalid);
QVERIFY(!spec.readMetaData(metaData("non-existing-file.json")));
- QCOMPARE(spec.state, PluginSpec::Invalid);
- QVERIFY(!spec.hasError);
- QVERIFY(spec.errorString.isEmpty());
+ QCOMPARE(spec.state(), PluginSpec::Invalid);
+ QVERIFY(!spec.hasError());
+ QVERIFY(spec.errorString().isEmpty());
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong2.json")));
- QCOMPARE(spec.state, PluginSpec::Invalid);
- QVERIFY(spec.hasError);
- QVERIFY(!spec.errorString.isEmpty());
+ QCOMPARE(spec.state(), PluginSpec::Invalid);
+ QVERIFY(spec.hasError());
+ QVERIFY(!spec.errorString().isEmpty());
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong3.json")));
- QCOMPARE(spec.state, PluginSpec::Invalid);
- QVERIFY(spec.hasError);
- QVERIFY(!spec.errorString.isEmpty());
+ QCOMPARE(spec.state(), PluginSpec::Invalid);
+ QVERIFY(spec.hasError());
+ QVERIFY(!spec.errorString().isEmpty());
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong4.json")));
- QCOMPARE(spec.state, PluginSpec::Invalid);
- QVERIFY(spec.hasError);
- QVERIFY(!spec.errorString.isEmpty());
+ QCOMPARE(spec.state(), PluginSpec::Invalid);
+ QVERIFY(spec.hasError());
+ QVERIFY(!spec.errorString().isEmpty());
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong5.json")));
- QCOMPARE(spec.state, PluginSpec::Invalid);
- QVERIFY(spec.hasError);
- QVERIFY(!spec.errorString.isEmpty());
+ QCOMPARE(spec.state(), PluginSpec::Invalid);
+ QVERIFY(spec.hasError());
+ QVERIFY(!spec.errorString().isEmpty());
}
void tst_PluginSpec::isValidVersion()
{
- QVERIFY(Internal::PluginSpecPrivate::isValidVersion("2"));
- QVERIFY(Internal::PluginSpecPrivate::isValidVersion("53"));
- QVERIFY(Internal::PluginSpecPrivate::isValidVersion("52_1"));
- QVERIFY(Internal::PluginSpecPrivate::isValidVersion("3.12"));
- QVERIFY(Internal::PluginSpecPrivate::isValidVersion("31.1_12"));
- QVERIFY(Internal::PluginSpecPrivate::isValidVersion("31.1.0"));
- QVERIFY(Internal::PluginSpecPrivate::isValidVersion("1.0.2_1"));
+ QVERIFY(PluginSpec::isValidVersion("2"));
+ QVERIFY(PluginSpec::isValidVersion("53"));
+ QVERIFY(PluginSpec::isValidVersion("52_1"));
+ QVERIFY(PluginSpec::isValidVersion("3.12"));
+ QVERIFY(PluginSpec::isValidVersion("31.1_12"));
+ QVERIFY(PluginSpec::isValidVersion("31.1.0"));
+ QVERIFY(PluginSpec::isValidVersion("1.0.2_1"));
- QVERIFY(!Internal::PluginSpecPrivate::isValidVersion(""));
- QVERIFY(!Internal::PluginSpecPrivate::isValidVersion("1..0"));
- QVERIFY(!Internal::PluginSpecPrivate::isValidVersion("1.0_"));
- QVERIFY(!Internal::PluginSpecPrivate::isValidVersion("1.0.0.0"));
+ QVERIFY(!PluginSpec::isValidVersion(""));
+ QVERIFY(!PluginSpec::isValidVersion("1..0"));
+ QVERIFY(!PluginSpec::isValidVersion("1.0_"));
+ QVERIFY(!PluginSpec::isValidVersion("1.0.0.0"));
}
void tst_PluginSpec::versionCompare()
{
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "3") == 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0.0", "3") == 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0", "3") == 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0.0_1", "3_1") == 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.0_21", "3_21") == 0);
+ QVERIFY(PluginSpec::versionCompare("3", "3") == 0);
+ QVERIFY(PluginSpec::versionCompare("3.0.0", "3") == 0);
+ QVERIFY(PluginSpec::versionCompare("3.0", "3") == 0);
+ QVERIFY(PluginSpec::versionCompare("3.0.0_1", "3_1") == 0);
+ QVERIFY(PluginSpec::versionCompare("3.0_21", "3_21") == 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "1") > 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "1.0_12") > 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("3_1", "3") > 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1.0_23", "3.1") > 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1_23", "3.1_12") > 0);
+ QVERIFY(PluginSpec::versionCompare("3", "1") > 0);
+ QVERIFY(PluginSpec::versionCompare("3", "1.0_12") > 0);
+ QVERIFY(PluginSpec::versionCompare("3_1", "3") > 0);
+ QVERIFY(PluginSpec::versionCompare("3.1.0_23", "3.1") > 0);
+ QVERIFY(PluginSpec::versionCompare("3.1_23", "3.1_12") > 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("1", "3") < 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("1.0_12", "3") < 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("3", "3_1") < 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1", "3.1.0_23") < 0);
- QVERIFY(Internal::PluginSpecPrivate::versionCompare("3.1_12", "3.1_23") < 0);
+ QVERIFY(PluginSpec::versionCompare("1", "3") < 0);
+ QVERIFY(PluginSpec::versionCompare("1.0_12", "3") < 0);
+ QVERIFY(PluginSpec::versionCompare("3", "3_1") < 0);
+ QVERIFY(PluginSpec::versionCompare("3.1", "3.1.0_23") < 0);
+ QVERIFY(PluginSpec::versionCompare("3.1_12", "3.1_23") < 0);
}
void tst_PluginSpec::provides()
{
- Internal::PluginSpecPrivate spec(0);
+ PluginSpecImpl spec;
QVERIFY(spec.readMetaData(metaData("testspecs/simplespec.json")));
+
QVERIFY(!spec.provides("SomeOtherPlugin", "2.2.3_9"));
QVERIFY(!spec.provides("MyPlugin", "2.2.3_10"));
QVERIFY(!spec.provides("MyPlugin", "2.2.4"));
@@ -211,112 +211,132 @@ void tst_PluginSpec::provides()
void tst_PluginSpec::experimental()
{
- Internal::PluginSpecPrivate spec(0);
+ PluginSpecImpl spec;
QVERIFY(spec.readMetaData(metaData("testspecs/simplespec_experimental.json")));
- QCOMPARE(spec.experimental, true);
- QCOMPARE(spec.enabledBySettings, false);
+
+ QCOMPARE(spec.isExperimental(), true);
+ QCOMPARE(spec.isEnabledBySettings(), false);
}
void tst_PluginSpec::locationAndPath()
{
- Internal::PluginSpecPrivate spec(0);
- QVERIFY(spec.read(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/") + libraryName(QLatin1String("test"))));
- QCOMPARE(spec.location, QString(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin")));
- QCOMPARE(spec.filePath, QString(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/") + libraryName(QLatin1String("test"))));
+ Utils::expected_str ps = PluginSpecImpl::read(
+ QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
+ + libraryName(QLatin1String("test")));
+ QVERIFY(ps);
+ PluginSpecImpl *spec = static_cast(ps.value());
+ QCOMPARE(spec->location(), QString(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin")));
+ QCOMPARE(spec->filePath(),
+ QString(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
+ + libraryName(QLatin1String("test"))));
}
void tst_PluginSpec::resolveDependencies()
{
QVector specs;
- PluginSpec *spec1 = Internal::PluginManagerPrivate::createSpec();
+ PluginSpec *spec1 = new PluginSpecImpl();
specs.append(spec1);
- Internal::PluginSpecPrivate *spec1Priv = Internal::PluginManagerPrivate::privateSpec(spec1);
- spec1Priv->readMetaData(metaData("testdependencies/spec1.json"));
- spec1Priv->state = PluginSpec::Read; // fake read state for plugin resolving
+ spec1->readMetaData(metaData("testdependencies/spec1.json"));
+ spec1->setState(PluginSpec::Read); // fake read state for plugin resolving
- PluginSpec *spec2 = Internal::PluginManagerPrivate::createSpec();
+ PluginSpec *spec2 = new PluginSpecImpl();
specs.append(spec2);
- Internal::PluginSpecPrivate *spec2Priv = Internal::PluginManagerPrivate::privateSpec(spec2);
- spec2Priv->readMetaData(metaData("testdependencies/spec2.json"));
- spec2Priv->state = PluginSpec::Read; // fake read state for plugin resolving
+ spec2->readMetaData(metaData("testdependencies/spec2.json"));
+ spec2->setState(PluginSpec::Read); // fake read state for plugin resolving
- PluginSpec *spec3 = Internal::PluginManagerPrivate::createSpec();
+ PluginSpec *spec3 = new PluginSpecImpl();
specs.append(spec3);
- Internal::PluginSpecPrivate *spec3Priv = Internal::PluginManagerPrivate::privateSpec(spec3);
- spec3Priv->readMetaData(metaData("testdependencies/spec3.json"));
- spec3Priv->state = PluginSpec::Read; // fake read state for plugin resolving
+ spec3->readMetaData(metaData("testdependencies/spec3.json"));
+ spec3->setState(PluginSpec::Read); // fake read state for plugin resolving
- PluginSpec *spec4 = Internal::PluginManagerPrivate::createSpec();
+ PluginSpec *spec4 = new PluginSpecImpl();
specs.append(spec4);
- Internal::PluginSpecPrivate *spec4Priv = Internal::PluginManagerPrivate::privateSpec(spec4);
- spec4Priv->readMetaData(metaData("testdependencies/spec4.json"));
- spec4Priv->state = PluginSpec::Read; // fake read state for plugin resolving
+ spec4->readMetaData(metaData("testdependencies/spec4.json"));
+ spec4->setState(PluginSpec::Read); // fake read state for plugin resolving
- PluginSpec *spec5 = Internal::PluginManagerPrivate::createSpec();
+ PluginSpec *spec5 = new PluginSpecImpl();
specs.append(spec5);
- Internal::PluginSpecPrivate *spec5Priv = Internal::PluginManagerPrivate::privateSpec(spec5);
- spec5Priv->readMetaData(metaData("testdependencies/spec5.json"));
- spec5Priv->state = PluginSpec::Read; // fake read state for plugin resolving
+ spec5->readMetaData(metaData("testdependencies/spec5.json"));
+ spec5->setState(PluginSpec::Read); // fake read state for plugin resolving
- QVERIFY(spec1Priv->resolveDependencies(specs));
- QCOMPARE(spec1Priv->dependencySpecs.size(), 2);
- QVERIFY(!spec1Priv->dependencySpecs.key(spec2).name.isEmpty());
- QVERIFY(!spec1Priv->dependencySpecs.key(spec3).name.isEmpty());
- QCOMPARE(spec1Priv->state, PluginSpec::Resolved);
- QVERIFY(!spec4Priv->resolveDependencies(specs));
- QVERIFY(spec4Priv->hasError);
- QCOMPARE(spec4Priv->state, PluginSpec::Read);
+ QVERIFY(spec1->resolveDependencies(specs));
+ QCOMPARE(spec1->dependencySpecs().size(), 2);
+ QVERIFY(!spec1->dependencySpecs().key(spec2).name.isEmpty());
+ QVERIFY(!spec1->dependencySpecs().key(spec3).name.isEmpty());
+ QCOMPARE(spec1->state(), PluginSpec::Resolved);
+ QVERIFY(!spec4->resolveDependencies(specs));
+ QVERIFY(spec4->hasError());
+ QCOMPARE(spec4->state(), PluginSpec::Read);
}
void tst_PluginSpec::loadLibrary()
{
- PluginSpec *ps = Internal::PluginManagerPrivate::createSpec();
- Internal::PluginSpecPrivate *spec = Internal::PluginManagerPrivate::privateSpec(ps);
- QVERIFY(spec->read(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/") + libraryName(QLatin1String("test"))));
+ Utils::expected_str ps = PluginSpecImpl::read(
+ QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
+ + libraryName(QLatin1String("test")));
+
+ QVERIFY(ps);
+ PluginSpecImpl *spec = static_cast(ps.value());
+
QVERIFY(spec->resolveDependencies(QVector()));
- QVERIFY2(spec->loadLibrary(), qPrintable(spec->errorString));
- QVERIFY(spec->plugin != 0);
- QVERIFY(QLatin1String(spec->plugin->metaObject()->className()) == QLatin1String("MyPlugin::MyPluginImpl"));
- QCOMPARE(spec->state, PluginSpec::Loaded);
- QVERIFY(!spec->hasError);
- QCOMPARE(spec->plugin, ps->plugin());
- delete ps;
+ QVERIFY2(spec->loadLibrary(), qPrintable(spec->errorString()));
+ QVERIFY(spec->plugin() != 0);
+ QVERIFY(QLatin1String(spec->plugin()->metaObject()->className())
+ == QLatin1String("MyPlugin::MyPluginImpl"));
+ QCOMPARE(spec->state(), PluginSpec::Loaded);
+ QVERIFY(!spec->hasError());
+
+ delete *ps;
}
void tst_PluginSpec::initializePlugin()
{
- Internal::PluginSpecPrivate spec(0);
- QVERIFY(spec.read(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/") + libraryName(QLatin1String("test"))));
- QVERIFY(spec.resolveDependencies(QVector()));
- QVERIFY2(spec.loadLibrary(), qPrintable(spec.errorString));
+ Utils::expected_str ps = PluginSpecImpl::read(
+ QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
+ + libraryName(QLatin1String("test")));
+ QVERIFY(ps);
+ PluginSpecImpl *spec = static_cast(ps.value());
+ QVERIFY(spec->resolveDependencies(QVector()));
+ QVERIFY2(spec->loadLibrary(), qPrintable(spec->errorString()));
bool isInitialized;
- QMetaObject::invokeMethod(spec.plugin, "isInitialized",
- Qt::DirectConnection, Q_RETURN_ARG(bool, isInitialized));
+ QMetaObject::invokeMethod(spec->plugin(),
+ "isInitialized",
+ Qt::DirectConnection,
+ Q_RETURN_ARG(bool, isInitialized));
QVERIFY(!isInitialized);
- QVERIFY(spec.initializePlugin());
- QCOMPARE(spec.state, PluginSpec::Initialized);
- QVERIFY(!spec.hasError);
- QMetaObject::invokeMethod(spec.plugin, "isInitialized",
- Qt::DirectConnection, Q_RETURN_ARG(bool, isInitialized));
+ QVERIFY(spec->initializePlugin());
+ QCOMPARE(spec->state(), PluginSpec::Initialized);
+ QVERIFY(!spec->hasError());
+ QMetaObject::invokeMethod(spec->plugin(),
+ "isInitialized",
+ Qt::DirectConnection,
+ Q_RETURN_ARG(bool, isInitialized));
QVERIFY(isInitialized);
}
void tst_PluginSpec::initializeExtensions()
{
- Internal::PluginSpecPrivate spec(0);
- QVERIFY(spec.read(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/") + libraryName(QLatin1String("test"))));
- QVERIFY(spec.resolveDependencies(QVector()));
- QVERIFY2(spec.loadLibrary(), qPrintable(spec.errorString));
+ Utils::expected_str ps = PluginSpecImpl::read(
+ QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
+ + libraryName(QLatin1String("test")));
+ QVERIFY(ps);
+ PluginSpecImpl *spec = static_cast(ps.value());
+ QVERIFY(spec->resolveDependencies(QVector()));
+ QVERIFY2(spec->loadLibrary(), qPrintable(spec->errorString()));
bool isExtensionsInitialized;
- QVERIFY(spec.initializePlugin());
- QMetaObject::invokeMethod(spec.plugin, "isExtensionsInitialized",
- Qt::DirectConnection, Q_RETURN_ARG(bool, isExtensionsInitialized));
+ QVERIFY(spec->initializePlugin());
+ QMetaObject::invokeMethod(spec->plugin(),
+ "isExtensionsInitialized",
+ Qt::DirectConnection,
+ Q_RETURN_ARG(bool, isExtensionsInitialized));
QVERIFY(!isExtensionsInitialized);
- QVERIFY(spec.initializeExtensions());
- QCOMPARE(spec.state, PluginSpec::Running);
- QVERIFY(!spec.hasError);
- QMetaObject::invokeMethod(spec.plugin, "isExtensionsInitialized",
- Qt::DirectConnection, Q_RETURN_ARG(bool, isExtensionsInitialized));
+ QVERIFY(spec->initializeExtensions());
+ QCOMPARE(spec->state(), PluginSpec::Running);
+ QVERIFY(!spec->hasError());
+ QMetaObject::invokeMethod(spec->plugin(),
+ "isExtensionsInitialized",
+ Qt::DirectConnection,
+ Q_RETURN_ARG(bool, isExtensionsInitialized));
QVERIFY(isExtensionsInitialized);
}
From cf53f157f7cb30a62753a9f59c44f8ca39ef7a13 Mon Sep 17 00:00:00 2001
From: Christian Stenger
Date: Thu, 15 Feb 2024 07:00:04 +0100
Subject: [PATCH 0008/1060] ExtensionSystem: Fix initialization and silence
logging
Avoids crash on start when running tests.
Change-Id: I924290f1d7c5d079ed96112e3d2375e53428221f
Reviewed-by: Marcus Tillmanns
---
src/libs/extensionsystem/pluginmanager.cpp | 2 +-
src/libs/extensionsystem/pluginspec.cpp | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/libs/extensionsystem/pluginmanager.cpp b/src/libs/extensionsystem/pluginmanager.cpp
index 43b8f3d2fa5..d8fdc096854 100644
--- a/src/libs/extensionsystem/pluginmanager.cpp
+++ b/src/libs/extensionsystem/pluginmanager.cpp
@@ -1792,7 +1792,7 @@ void PluginManagerPrivate::readPluginPaths()
for (const QString &pluginFile : pluginFiles(pluginPaths)) {
expected_str spec = PluginSpecImpl::read(pluginFile);
if (!spec) {
- qCWarning(pluginLog).noquote()
+ qCInfo(pluginLog).noquote()
<< QString("Ignoring plugin \"%1\" because: %2").arg(pluginFile).arg(spec.error());
continue;
}
diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp
index 8740854e7e5..abed26c7fbe 100644
--- a/src/libs/extensionsystem/pluginspec.cpp
+++ b/src/libs/extensionsystem/pluginspec.cpp
@@ -175,7 +175,7 @@ public:
std::optional loader;
std::optional staticPlugin;
- IPlugin *plugin;
+ IPlugin *plugin = nullptr;
};
class PluginSpecPrivate
From 837e951b29240d28b4c5849acae04d2ebbcd03f1 Mon Sep 17 00:00:00 2001
From: Christian Kandeler
Date: Wed, 7 Feb 2024 14:12:11 +0100
Subject: [PATCH 0009/1060] CppEditor: Add curly braces for more control
statements
Fixes: QTCREATORBUG-24542
Change-Id: I3e0893e1c736730d94e2c9ab2baa0aa580393fe4
Reviewed-by:
Reviewed-by: Christian Stenger
Reviewed-by: Qt CI Bot
---
src/plugins/cppeditor/cppquickfix_test.cpp | 96 ++++++++++++++++--
src/plugins/cppeditor/cppquickfix_test.h | 1 +
src/plugins/cppeditor/cppquickfixes.cpp | 109 ++++++++++++++-------
src/plugins/cppeditor/cppquickfixes.h | 6 +-
4 files changed, 166 insertions(+), 46 deletions(-)
diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp
index 48c9bbc68af..56ae513a8a1 100644
--- a/src/plugins/cppeditor/cppquickfix_test.cpp
+++ b/src/plugins/cppeditor/cppquickfix_test.cpp
@@ -8229,29 +8229,105 @@ void QuickfixTest::testExtractLiteralAsParameterNotTriggeringForInvalidCode()
QuickFixOperationTest(testDocuments, &factory);
}
-void QuickfixTest::testAddCurlyBraces()
+void QuickfixTest::testAddCurlyBraces_data()
{
- QList testDocuments;
- const QByteArray original = R"delim(
+ QTest::addColumn("original");
+ QTest::addColumn("expected");
+
+ QByteArray original = R"delim(
void MyObject::f()
{
@if (true)
emit mySig();
-}
-)delim";
- const QByteArray expected = R"delim(
+})delim";
+ QByteArray expected = R"delim(
void MyObject::f()
{
if (true) {
emit mySig();
}
+})delim";
+ QTest::newRow("if") << original << expected;
+
+ original = R"delim(
+void MyObject::f()
+{
+ @while (true)
+ emit mySig();
+})delim";
+ expected = R"delim(
+void MyObject::f()
+{
+ while (true) {
+ emit mySig();
+ }
+})delim";
+ QTest::newRow("while") << original << expected;
+
+ original = R"delim(
+void MyObject::f()
+{
+ @for (int i = 0; i < 10; ++i)
+ emit mySig();
+})delim";
+ expected = R"delim(
+void MyObject::f()
+{
+ for (int i = 0; i < 10; ++i) {
+ emit mySig();
+ }
+})delim";
+ QTest::newRow("for") << original << expected;
+
+ original = R"delim(
+void MyObject::f()
+{
+ @for (int i : list)
+ emit mySig();
+})delim";
+ expected = R"delim(
+void MyObject::f()
+{
+ for (int i : list) {
+ emit mySig();
+ }
+})delim";
+ QTest::newRow("range-based for") << original << expected;
+
+ original = R"delim(
+void MyObject::f()
+{
+ @do
+ emit mySig();
+ while (true);
+})delim";
+ expected = R"delim(
+void MyObject::f()
+{
+ do {
+ emit mySig();
+ } while (true);
+})delim";
+ QTest::newRow("do") << original << expected;
+
+ original = R"delim(
+void MyObject::f()
+{
+ @do {
+ emit mySig();
+ } while (true);
+})delim";
+ expected.clear();
+ QTest::newRow("already has braces") << original << expected;
}
-)delim";
- testDocuments << CppTestDocument::create("file.cpp", original, expected);
- AddBracesToIf factory;
- QuickFixOperationTest(testDocuments, &factory);
+void QuickfixTest::testAddCurlyBraces()
+{
+ QFETCH(QByteArray, original);
+ QFETCH(QByteArray, expected);
+ AddBracesToControlStatement factory;
+ QuickFixOperationTest({CppTestDocument::create("file.cpp", original, expected)}, &factory);
}
void QuickfixTest::testConvertQt4ConnectConnectOutOfClass()
diff --git a/src/plugins/cppeditor/cppquickfix_test.h b/src/plugins/cppeditor/cppquickfix_test.h
index 4d734c9c09c..917abe19c73 100644
--- a/src/plugins/cppeditor/cppquickfix_test.h
+++ b/src/plugins/cppeditor/cppquickfix_test.h
@@ -209,6 +209,7 @@ private slots:
void testExtractLiteralAsParameterMemberFunctionSeparateFiles();
void testExtractLiteralAsParameterNotTriggeringForInvalidCode();
+ void testAddCurlyBraces_data();
void testAddCurlyBraces();
void testRemoveUsingNamespace_data();
diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp
index 90563ccd33d..bf3f1375117 100644
--- a/src/plugins/cppeditor/cppquickfixes.cpp
+++ b/src/plugins/cppeditor/cppquickfixes.cpp
@@ -764,13 +764,49 @@ void SplitSimpleDeclaration::doMatch(const CppQuickFixInterface &interface,
}
namespace {
+template Statement *asControlStatement(AST *node)
+{
+ if constexpr (std::is_same_v)
+ return node->asIfStatement();
+ if constexpr (std::is_same_v)
+ return node->asWhileStatement();
+ if constexpr (std::is_same_v)
+ return node->asForStatement();
+ if constexpr (std::is_same_v)
+ return node->asRangeBasedForStatement();
+ if constexpr (std::is_same_v)
+ return node->asDoStatement();
+ return nullptr;
+}
-class AddBracesToIfOp: public CppQuickFixOperation
+template
+int triggerToken(const Statement *statement)
+{
+ if constexpr (std::is_same_v)
+ return statement->if_token;
+ if constexpr (std::is_same_v)
+ return statement->while_token;
+ if constexpr (std::is_same_v)
+ return statement->do_token;
+ if constexpr (std::is_same_v
+ || std::is_same_v) {
+ return statement->for_token;
+ }
+}
+
+template
+int tokenToInsertOpeningBraceAfter(const Statement *statement)
+{
+ if constexpr (std::is_same_v)
+ return statement->do_token;
+ return statement->rparen_token;
+}
+
+template class AddBracesToControlStatementOp : public CppQuickFixOperation
{
public:
- AddBracesToIfOp(const CppQuickFixInterface &interface, int priority,
- const IfStatementAST *statement)
- : CppQuickFixOperation(interface, priority)
+ AddBracesToControlStatementOp(const CppQuickFixInterface &interface, const Statement *statement)
+ : CppQuickFixOperation(interface, 0)
, _statement(statement)
{
setDescription(Tr::tr("Add Curly Braces"));
@@ -783,51 +819,58 @@ public:
ChangeSet changes;
- const int start = currentFile->endOf(_statement->rparen_token);
+ const int start = currentFile->endOf(tokenToInsertOpeningBraceAfter(_statement));
changes.insert(start, QLatin1String(" {"));
- const int end = currentFile->endOf(_statement->statement->lastToken() - 1);
- changes.insert(end, QLatin1String("\n}"));
+ if constexpr (std::is_same_v) {
+ const int end = currentFile->startOf(_statement->while_token);
+ changes.insert(end, QLatin1String("} "));
+ } else {
+ const int end = currentFile->endOf(_statement->statement->lastToken() - 1);
+ changes.insert(end, QLatin1String("\n}"));
+ }
+ // TODO: For if statements, also bracify all else cases.
+ // Also check all else cases in the factory.
currentFile->setChangeSet(changes);
currentFile->apply();
}
private:
- const IfStatementAST * const _statement;
+ const Statement * const _statement;
};
} // anonymous namespace
-void AddBracesToIf::doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result)
+template
+bool checkControlStatementsHelper(const CppQuickFixInterface &interface, QuickFixOperations &result)
{
- const QList &path = interface.path();
- if (path.isEmpty())
- return;
+ Statement * const statement = asControlStatement(interface.path().last());
+ if (!statement)
+ return false;
- // show when we're on the 'if' of an if statement
- int index = path.size() - 1;
- IfStatementAST *ifStatement = path.at(index)->asIfStatement();
- if (ifStatement && interface.isCursorOn(ifStatement->if_token) && ifStatement->statement
- && !ifStatement->statement->asCompoundStatement()) {
- result << new AddBracesToIfOp(interface, index, ifStatement);
- return;
+ if (interface.isCursorOn(triggerToken(statement)) && statement->statement
+ && !statement->statement->asCompoundStatement()) {
+ result << new AddBracesToControlStatementOp(interface, statement);
}
+ return true;
+}
- // or if we're on the statement contained in the if
- // ### This may not be such a good idea, consider nested ifs...
- for (; index != -1; --index) {
- IfStatementAST *ifStatement = path.at(index)->asIfStatement();
- if (ifStatement && ifStatement->statement
- && interface.isCursorOn(ifStatement->statement)
- && !ifStatement->statement->asCompoundStatement()) {
- result << new AddBracesToIfOp(interface, index, ifStatement);
- return;
- }
- }
+template
+void checkControlStatements(const CppQuickFixInterface &interface, QuickFixOperations &result)
+{
+ (... || checkControlStatementsHelper(interface, result));
+}
- // ### This could very well be extended to the else branch
- // and other nodes entirely.
+void AddBracesToControlStatement::doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result)
+{
+ if (interface.path().isEmpty())
+ return;
+ checkControlStatements(interface, result);
}
namespace {
@@ -9969,7 +10012,7 @@ void createCppQuickFixes()
new SplitIfStatement;
new SplitSimpleDeclaration;
- new AddBracesToIf;
+ new AddBracesToControlStatement;
new RearrangeParamDeclarationList;
new ReformatPointerDeclaration;
diff --git a/src/plugins/cppeditor/cppquickfixes.h b/src/plugins/cppeditor/cppquickfixes.h
index 99904ffcb19..10f82c9dda3 100644
--- a/src/plugins/cppeditor/cppquickfixes.h
+++ b/src/plugins/cppeditor/cppquickfixes.h
@@ -287,7 +287,7 @@ public:
};
/*!
- Add curly braces to a if statement that doesn't already contain a
+ Add curly braces to a control statement that doesn't already contain a
compound statement. I.e.
if (a)
@@ -297,9 +297,9 @@ public:
b;
}
- Activates on: the if
+ Activates on: the keyword
*/
-class AddBracesToIf: public CppQuickFixFactory
+class AddBracesToControlStatement : public CppQuickFixFactory
{
public:
void doMatch(const CppQuickFixInterface &interface, QuickFixOperations &result) override;
From f00666a9853c8554f8d6b2a16aaf4a5f9521dae1 Mon Sep 17 00:00:00 2001
From: Christian Kandeler
Date: Wed, 7 Feb 2024 17:45:29 +0100
Subject: [PATCH 0010/1060] ProjectExplorer: Accept plain folder nodes as drag
& drop targets
As opposed to just project nodes.
Task-number: QTCREATORBUG-26545
Change-Id: I33eb2623763fdfacb9b6b8bb1bcd6b4626b3d71e
Reviewed-by:
Reviewed-by: Christian Stenger
---
src/plugins/projectexplorer/projectmodels.cpp | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/src/plugins/projectexplorer/projectmodels.cpp b/src/plugins/projectexplorer/projectmodels.cpp
index dcbd3a89c89..53f33f58b31 100644
--- a/src/plugins/projectexplorer/projectmodels.cpp
+++ b/src/plugins/projectexplorer/projectmodels.cpp
@@ -679,6 +679,8 @@ bool FlatModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int r
return n->parentProjectNode() != sourceProjectNode; })) {
return true;
}
+ FolderNode * const sourceFolderNode = fileNodes.first()->parentFolderNode();
+ const bool sourceNodeIsSubDir = sourceFolderNode != sourceProjectNode;
Node *targetNode = nodeForIndex(index(row, column, parent));
if (!targetNode)
targetNode = nodeForIndex(parent);
@@ -687,20 +689,22 @@ bool FlatModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int r
if (!targetProjectNode)
targetProjectNode = targetNode->parentProjectNode();
QTC_ASSERT(targetProjectNode, return true);
- if (sourceProjectNode == targetProjectNode)
+ const bool targetNodeIsSubDir = targetNode != targetProjectNode && targetNode->asFolderNode();
+ if (sourceProjectNode == targetProjectNode && !targetNodeIsSubDir && !sourceNodeIsSubDir)
return true;
// Node weirdness: Sometimes the "file path" is a directory, sometimes it's a file...
- const auto dirForProjectNode = [](const ProjectNode *pNode) {
- const FilePath dir = pNode->filePath();
+ const auto dirForFolderNode = [](const FolderNode *node) {
+ const FilePath dir = node->filePath();
if (dir.isDir())
return dir;
return FilePath::fromString(dir.toFileInfo().path());
};
- FilePath targetDir = dirForProjectNode(targetProjectNode);
+ FilePath targetDir = dirForFolderNode(targetNodeIsSubDir ? targetNode->asFolderNode()
+ : targetProjectNode);
// Ask the user what to do now: Copy or add? With or without file transfer?
- DropFileDialog dlg(targetDir == dirForProjectNode(sourceProjectNode) ? FilePath() : targetDir);
+ DropFileDialog dlg(targetDir == dirForFolderNode(sourceFolderNode) ? FilePath() : targetDir);
if (dlg.exec() != QDialog::Accepted)
return true;
if (!dlg.targetDir().isEmpty())
From 5334081270b97d1021e8101f6a25e6bfba657243 Mon Sep 17 00:00:00 2001
From: Eike Ziller
Date: Thu, 15 Feb 2024 12:04:41 +0100
Subject: [PATCH 0011/1060] Bump version to 14.0.0-beta1
Change-Id: I62f28969f68889f628fb37e8a1eb390a62bd6e46
Reviewed-by: David Schulz
---
cmake/QtCreatorIDEBranding.cmake | 6 +++---
qbs/modules/qtc/qtc.qbs | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake
index 275454a6684..e37467b6616 100644
--- a/cmake/QtCreatorIDEBranding.cmake
+++ b/cmake/QtCreatorIDEBranding.cmake
@@ -1,6 +1,6 @@
-set(IDE_VERSION "12.0.82") # The IDE version.
-set(IDE_VERSION_COMPAT "12.0.82") # The IDE Compatibility version.
-set(IDE_VERSION_DISPLAY "13.0.0-beta1") # The IDE display version.
+set(IDE_VERSION "13.0.82") # The IDE version.
+set(IDE_VERSION_COMPAT "13.0.82") # The IDE Compatibility version.
+set(IDE_VERSION_DISPLAY "14.0.0-beta1") # The IDE display version.
set(IDE_COPYRIGHT_YEAR "2024") # The IDE current copyright year.
set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation.
diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs
index 1fe9fe91354..cf145a73d12 100644
--- a/qbs/modules/qtc/qtc.qbs
+++ b/qbs/modules/qtc/qtc.qbs
@@ -4,14 +4,14 @@ import qbs.FileInfo
import qbs.Utilities
Module {
- property string qtcreator_display_version: '13.0.0-beta1'
- property string ide_version_major: '12'
+ property string qtcreator_display_version: '14.0.0-beta1'
+ property string ide_version_major: '13'
property string ide_version_minor: '0'
property string ide_version_release: '82'
property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.'
+ ide_version_release
- property string ide_compat_version_major: '12'
+ property string ide_compat_version_major: '13'
property string ide_compat_version_minor: '0'
property string ide_compat_version_release: '82'
property string qtcreator_compat_version: ide_compat_version_major + '.'
From 7c5a0e6bb2740d31de82e78e2316727258851845 Mon Sep 17 00:00:00 2001
From: hjk
Date: Thu, 15 Feb 2024 17:50:52 +0100
Subject: [PATCH 0012/1060] Rename RunControl::aspect to RunControl::aspectData
It's the "persisted" form of the content of the original aspect's data,
calling it 'aspect' already confused me a few times.
Change-Id: I88a6f76f0ca39d3d36dde9b84287032ceecf7033
Reviewed-by: Christian Kandeler
---
.../android/androidqmlpreviewworker.cpp | 2 +-
src/plugins/android/androidrunnerworker.cpp | 4 ++--
.../debugservers/gdb/gdbserverprovider.cpp | 4 ++--
.../debugservers/uvsc/uvscserverprovider.cpp | 2 +-
src/plugins/debugger/debuggerruncontrol.cpp | 12 +++++------
src/plugins/debugger/terminal.cpp | 2 +-
src/plugins/ios/iosrunner.cpp | 6 +++---
.../mcusupport/mcusupportrunconfiguration.cpp | 2 +-
.../perfprofiler/perfprofilerruncontrol.cpp | 2 +-
src/plugins/projectexplorer/runcontrol.cpp | 10 +++++-----
src/plugins/projectexplorer/runcontrol.h | 8 ++++----
.../qmlpreview/qmlpreviewruncontrol.cpp | 2 +-
src/plugins/qmlprofiler/qmlprofilertool.cpp | 2 +-
.../qmlmultilanguageaspect.cpp | 2 +-
src/plugins/qnx/slog2inforunner.cpp | 2 +-
.../appmanagerruncontrol.cpp | 20 +++++++++----------
src/plugins/valgrind/valgrindengine.cpp | 2 +-
.../webassemblyrunconfiguration.cpp | 2 +-
18 files changed, 43 insertions(+), 43 deletions(-)
diff --git a/src/plugins/android/androidqmlpreviewworker.cpp b/src/plugins/android/androidqmlpreviewworker.cpp
index 06a14edc06e..dceedd36734 100644
--- a/src/plugins/android/androidqmlpreviewworker.cpp
+++ b/src/plugins/android/androidqmlpreviewworker.cpp
@@ -459,7 +459,7 @@ bool AndroidQmlPreviewWorker::startPreviewApp()
const QDir destDir(apkInfo()->uploadDir);
const QString qmlrcPath = destDir.filePath(m_uploadInfo.uploadPackage.baseName()
+ packageSuffix);
- const QStringList envVars = m_rc->aspect()->environment.toStringList();
+ const QStringList envVars = m_rc->aspectData()->environment.toStringList();
const QStringList command {
"am", "start",
diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp
index 6cba25a0179..f21928f27d8 100644
--- a/src/plugins/android/androidrunnerworker.cpp
+++ b/src/plugins/android/androidrunnerworker.cpp
@@ -210,7 +210,7 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
auto runControl = runner->runControl();
m_useLldb = Debugger::DebuggerKitAspect::engineType(runControl->kit())
== Debugger::LldbEngineType;
- auto aspect = runControl->aspect();
+ auto aspect = runControl->aspectData();
Utils::Id runMode = runControl->runMode();
const bool debuggingMode = runMode == ProjectExplorer::Constants::DEBUG_RUN_MODE;
m_useCppDebugger = debuggingMode && aspect->useCppDebugger;
@@ -242,7 +242,7 @@ AndroidRunnerWorker::AndroidRunnerWorker(RunWorker *runner, const QString &packa
m_deviceSerialNumber = AndroidManager::deviceSerialNumber(target);
m_apiLevel = AndroidManager::deviceApiLevel(target);
- m_extraEnvVars = runControl->aspect()->environment;
+ m_extraEnvVars = runControl->aspectData()->environment;
qCDebug(androidRunWorkerLog).noquote() << "Environment variables for the app"
<< m_extraEnvVars.toStringList();
diff --git a/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp b/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp
index 3da6b06254f..885e20fac42 100644
--- a/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp
+++ b/src/plugins/baremetal/debugservers/gdb/gdbserverprovider.cpp
@@ -139,7 +139,7 @@ bool GdbServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMessa
{
QTC_ASSERT(runTool, return false);
const RunControl *runControl = runTool->runControl();
- const auto exeAspect = runControl->aspect();
+ const auto exeAspect = runControl->aspectData();
QTC_ASSERT(exeAspect, return false);
const FilePath bin = FilePath::fromString(exeAspect->executable.path());
@@ -155,7 +155,7 @@ bool GdbServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMessa
ProcessRunData inferior;
inferior.command.setExecutable(bin);
- if (const auto argAspect = runControl->aspect())
+ if (const auto argAspect = runControl->aspectData())
inferior.command.setArguments(argAspect->arguments);
runTool->setInferior(inferior);
runTool->setSymbolFile(bin);
diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp
index f77a0ce0cfd..ed84508322c 100644
--- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp
+++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp
@@ -169,7 +169,7 @@ bool UvscServerProvider::aboutToRun(DebuggerRunTool *runTool, QString &errorMess
{
QTC_ASSERT(runTool, return false);
const RunControl *runControl = runTool->runControl();
- const auto exeAspect = runControl->aspect();
+ const auto exeAspect = runControl->aspectData();
QTC_ASSERT(exeAspect, return false);
const FilePath bin = exeAspect->executable;
diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp
index 4a0f20b8d64..d6fd83e7637 100644
--- a/src/plugins/debugger/debuggerruncontrol.cpp
+++ b/src/plugins/debugger/debuggerruncontrol.cpp
@@ -529,8 +529,8 @@ void DebuggerRunTool::start()
return;
}
- if (auto interpreterAspect = runControl()->aspect()) {
- if (auto mainScriptAspect = runControl()->aspect()) {
+ if (auto interpreterAspect = runControl()->aspectData()) {
+ if (auto mainScriptAspect = runControl()->aspectData()) {
const FilePath mainScript = mainScriptAspect->filePath;
const FilePath interpreter = interpreterAspect->filePath;
if (!interpreter.isEmpty() && mainScript.endsWith(".py")) {
@@ -831,11 +831,11 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm
m_runParameters.displayName = runControl->displayName();
- if (auto symbolsAspect = runControl->aspect())
+ if (auto symbolsAspect = runControl->aspectData())
m_runParameters.symbolFile = symbolsAspect->filePath;
- if (auto terminalAspect = runControl->aspect())
+ if (auto terminalAspect = runControl->aspectData())
m_runParameters.useTerminal = terminalAspect->useTerminal;
- if (auto runAsRootAspect = runControl->aspect())
+ if (auto runAsRootAspect = runControl->aspectData())
m_runParameters.runAsRoot = runAsRootAspect->value;
Kit *kit = runControl->kit();
@@ -850,7 +850,7 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm
if (QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(kit))
m_runParameters.qtSourceLocation = qtVersion->sourcePath();
- if (auto aspect = runControl->aspect()) {
+ if (auto aspect = runControl->aspectData()) {
if (!aspect->useCppDebugger)
m_runParameters.cppEngineType = NoEngineType;
m_runParameters.isQmlDebugging = aspect->useQmlDebugger;
diff --git a/src/plugins/debugger/terminal.cpp b/src/plugins/debugger/terminal.cpp
index 18092f132fe..54969c5281d 100644
--- a/src/plugins/debugger/terminal.cpp
+++ b/src/plugins/debugger/terminal.cpp
@@ -175,7 +175,7 @@ void TerminalRunner::start()
ProcessRunData stub = m_stubRunnable();
bool runAsRoot = false;
- if (auto runAsRootAspect = runControl()->aspect())
+ if (auto runAsRootAspect = runControl()->aspectData())
runAsRoot = runAsRootAspect->value;
m_stubProc = new Process(this);
diff --git a/src/plugins/ios/iosrunner.cpp b/src/plugins/ios/iosrunner.cpp
index e2ed4191292..c58c5731ba3 100644
--- a/src/plugins/ios/iosrunner.cpp
+++ b/src/plugins/ios/iosrunner.cpp
@@ -114,7 +114,7 @@ DeviceCtlRunner::DeviceCtlRunner(RunControl *runControl)
: RunWorker(runControl)
{
setId("IosDeviceCtlRunner");
- const IosDeviceTypeAspect::Data *data = runControl->aspect();
+ const IosDeviceTypeAspect::Data *data = runControl->aspectData();
QTC_ASSERT(data, return);
m_bundlePath = data->bundleDirectory;
m_arguments = ProcessArgs::splitArgs(runControl->commandLine().arguments(), OsTypeMac);
@@ -436,7 +436,7 @@ IosRunner::IosRunner(RunControl *runControl)
{
setId("IosRunner");
stopRunningRunControl(runControl);
- const IosDeviceTypeAspect::Data *data = runControl->aspect();
+ const IosDeviceTypeAspect::Data *data = runControl->aspectData();
QTC_ASSERT(data, return);
m_bundleDir = data->bundleDirectory;
m_device = DeviceKitAspect::device(runControl->kit());
@@ -826,7 +826,7 @@ void IosDebugSupport::start()
setIosPlatform("ios-simulator");
}
- const IosDeviceTypeAspect::Data *data = runControl()->aspect();
+ const IosDeviceTypeAspect::Data *data = runControl()->aspectData();
QTC_ASSERT(data, reportFailure("Broken IosDeviceTypeAspect setup."); return);
setRunControlName(data->applicationName);
diff --git a/src/plugins/mcusupport/mcusupportrunconfiguration.cpp b/src/plugins/mcusupport/mcusupportrunconfiguration.cpp
index 9e936c4faeb..260b908c854 100644
--- a/src/plugins/mcusupport/mcusupportrunconfiguration.cpp
+++ b/src/plugins/mcusupport/mcusupportrunconfiguration.cpp
@@ -81,7 +81,7 @@ public:
{
setStartModifier([this, runControl] {
const Target *target = runControl->target();
- setCommandLine({cmakeFilePath(target), runControl->aspect()->value,
+ setCommandLine({cmakeFilePath(target), runControl->aspectData()->value,
CommandLine::Raw});
setWorkingDirectory(target->activeBuildConfiguration()->buildDirectory());
setEnvironment(target->activeBuildConfiguration()->environment());
diff --git a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp
index 2d35f1790ee..797fb4c2ade 100644
--- a/src/plugins/perfprofiler/perfprofilerruncontrol.cpp
+++ b/src/plugins/perfprofiler/perfprofilerruncontrol.cpp
@@ -97,7 +97,7 @@ public:
void start() final
{
- auto perfAspect = runControl()->aspect();
+ auto perfAspect = runControl()->aspectData();
QTC_ASSERT(perfAspect, reportFailure(); return);
PerfSettings *settings = static_cast(perfAspect->currentSettings);
QTC_ASSERT(settings, reportFailure(); return);
diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp
index d2481f2ac63..0de0ff04628 100644
--- a/src/plugins/projectexplorer/runcontrol.cpp
+++ b/src/plugins/projectexplorer/runcontrol.cpp
@@ -852,7 +852,7 @@ void RunControlPrivate::showError(const QString &msg)
void RunControl::setupFormatter(OutputFormatter *formatter) const
{
QList parsers = createOutputParsers(target());
- if (const auto customParsersAspect = aspect()) {
+ if (const auto customParsersAspect = aspectData()) {
for (const Id id : std::as_const(customParsersAspect->parsers)) {
if (auto parser = createCustomParserFromId(id))
parsers << parser;
@@ -969,12 +969,12 @@ const MacroExpander *RunControl::macroExpander() const
return d->macroExpander;
}
-const BaseAspect::Data *RunControl::aspect(Id instanceId) const
+const BaseAspect::Data *RunControl::aspectData(Id instanceId) const
{
return d->aspectData.aspect(instanceId);
}
-const BaseAspect::Data *RunControl::aspect(BaseAspect::Data::ClassId classId) const
+const BaseAspect::Data *RunControl::aspectData(BaseAspect::Data::ClassId classId) const
{
return d->aspectData.aspect(classId);
}
@@ -1502,11 +1502,11 @@ void SimpleTargetRunner::start()
d->m_startModifier();
bool useTerminal = false;
- if (auto terminalAspect = runControl()->aspect())
+ if (auto terminalAspect = runControl()->aspectData())
useTerminal = terminalAspect->useTerminal;
bool runAsRoot = false;
- if (auto runAsRootAspect = runControl()->aspect())
+ if (auto runAsRootAspect = runControl()->aspectData())
runAsRoot = runAsRootAspect->value;
d->m_stopForced = false;
diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h
index d969ca47c5f..629fff8346a 100644
--- a/src/plugins/projectexplorer/runcontrol.h
+++ b/src/plugins/projectexplorer/runcontrol.h
@@ -186,10 +186,10 @@ public:
Kit *kit() const;
const Utils::MacroExpander *macroExpander() const;
- const Utils::BaseAspect::Data *aspect(Utils::Id instanceId) const;
- const Utils::BaseAspect::Data *aspect(Utils::BaseAspect::Data::ClassId classId) const;
- template const typename T::Data *aspect() const {
- return dynamic_cast(aspect(&T::staticMetaObject));
+ const Utils::BaseAspect::Data *aspectData(Utils::Id instanceId) const;
+ const Utils::BaseAspect::Data *aspectData(Utils::BaseAspect::Data::ClassId classId) const;
+ template const typename T::Data *aspectData() const {
+ return dynamic_cast(aspectData(&T::staticMetaObject));
}
QString buildKey() const;
diff --git a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp
index 209bc06d1d3..41bac4cd8e5 100644
--- a/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp
+++ b/src/plugins/qmlpreview/qmlpreviewruncontrol.cpp
@@ -206,7 +206,7 @@ public:
setStartModifier([this, runControl, serverUrl] {
CommandLine cmd = commandLine();
- if (const auto aspect = runControl->aspect()) {
+ if (const auto aspect = runControl->aspectData()) {
const auto qmlBuildSystem = qobject_cast(
runControl->target()->buildSystem());
QTC_ASSERT(qmlBuildSystem, return);
diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp
index aa2397a18a4..753d7ea0145 100644
--- a/src/plugins/qmlprofiler/qmlprofilertool.cpp
+++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp
@@ -353,7 +353,7 @@ void QmlProfilerTool::finalizeRunControl(QmlProfilerRunner *runWorker)
{
d->m_toolBusy = true;
auto runControl = runWorker->runControl();
- if (auto aspect = runControl->aspect()) {
+ if (auto aspect = runControl->aspectData()) {
if (auto settings = static_cast(aspect->currentSettings)) {
d->m_profilerConnections->setFlushInterval(settings->flushEnabled() ?
settings->flushInterval() : 0);
diff --git a/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp b/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp
index 1b3238a425b..ae16f09fc22 100644
--- a/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp
+++ b/src/plugins/qmlprojectmanager/qmlmultilanguageaspect.cpp
@@ -69,7 +69,7 @@ QmlMultiLanguageAspect::QmlMultiLanguageAspect(AspectContainer *container)
connect(this, &BoolAspect::changed, this, [this] {
for (RunControl *runControl : ProjectExplorerPlugin::allRunControls()) {
- if (auto aspect = runControl->aspect()) {
+ if (auto aspect = runControl->aspectData()) {
if (auto origin = aspect->origin; origin == this)
runControl->initiateStop();
}
diff --git a/src/plugins/qnx/slog2inforunner.cpp b/src/plugins/qnx/slog2inforunner.cpp
index 71264da1e7c..47aa850e819 100644
--- a/src/plugins/qnx/slog2inforunner.cpp
+++ b/src/plugins/qnx/slog2inforunner.cpp
@@ -22,7 +22,7 @@ Slog2InfoRunner::Slog2InfoRunner(RunControl *runControl)
: RunWorker(runControl)
{
setId("Slog2InfoRunner");
- m_applicationId = runControl->aspect()->executable.fileName();
+ m_applicationId = runControl->aspectData()->executable.fileName();
// See QTCREATORBUG-10712 for details.
// We need to limit length of ApplicationId to 63 otherwise it would not match one in slog2info.
diff --git a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp
index ec1aa7244ed..37ade563161 100644
--- a/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp
+++ b/src/plugins/qtapplicationmanager/appmanagerruncontrol.cpp
@@ -53,12 +53,12 @@ public:
});
setStartModifier([this, runControl] {
- FilePath controller = runControl->aspect()->filePath;
- QString appId = runControl->aspect()->value;
- QString instanceId = runControl->aspect()->value;
- QString documentUrl = runControl->aspect()->value;
+ FilePath controller = runControl->aspectData()->filePath;
+ QString appId = runControl->aspectData()->value;
+ QString instanceId = runControl->aspectData()->value;
+ QString documentUrl = runControl->aspectData()->value;
QStringList envVars;
- if (auto envAspect = runControl->aspect())
+ if (auto envAspect = runControl->aspectData())
envVars = envAspect->environment.toStringList();
// Always use the default environment to start the appman-controller in
@@ -115,12 +115,12 @@ public:
addStartDependency(m_portsGatherer);
setStartModifier([this, runControl] {
- FilePath controller = runControl->aspect()->filePath;
- QString appId = runControl->aspect()->value;
- QString instanceId = runControl->aspect()->value;
- QString documentUrl = runControl->aspect()->value;
+ FilePath controller = runControl->aspectData()->filePath;
+ QString appId = runControl->aspectData()->value;
+ QString instanceId = runControl->aspectData()->value;
+ QString documentUrl = runControl->aspectData()->value;
QStringList envVars;
- if (auto envAspect = runControl->aspect