forked from qt-creator/qt-creator
Android/ProjectExplorer: Fix crash when removing multiple Android Qts
That were configured for a project. The crash is triggered by a messy combination of the Android automatic kit creation, project window update, and automatic creation of Qt versions and kits by the automatic project importers, including a mess of the listener pattern without any atomicity. - the user removes the Qt versions - the Android plugin updates the automatic kits and individually reports the removed kits (*) - that triggers an update of the project window and an update of the target setup page (even if that is not shown, but that's yet another issue) - that triggers the project importers, which add Qt versions, which in turn triggers another update of automatic kits in the Android plugin - while that is still in the reporting loop at (*) - that leads to the crash, because the state at this point of time is a mess This minimal fix of the specific crash makes the kit update reporting in the Android plugin at (*) "more atomic", and the same for similar code in the iOS plugin. Fixes: QTCREATORBUG-30347 Change-Id: I2bea6fb735abcaa34469fc43f44aa37313f70429 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Alessandro Portale <alessandro.portale@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -1470,8 +1470,7 @@ void AndroidConfigurations::updateAutomaticKitList()
|
||||
}
|
||||
// cleanup any mess that might have existed before, by removing all Android kits that
|
||||
// existed before, but weren't re-used
|
||||
for (Kit *k : unhandledKits)
|
||||
KitManager::deregisterKit(k);
|
||||
KitManager::deregisterKits(unhandledKits);
|
||||
}
|
||||
|
||||
Environment AndroidConfig::toolsEnvironment() const
|
||||
|
@@ -305,8 +305,7 @@ void IosConfigurations::updateAutomaticKitList()
|
||||
existingKits.subtract(resultingKits);
|
||||
qCDebug(kitSetupLog) << "Removing unused kits:";
|
||||
printKits(existingKits);
|
||||
for (Kit *kit : std::as_const(existingKits))
|
||||
KitManager::deregisterKit(kit);
|
||||
KitManager::deregisterKits(toList(existingKits));
|
||||
}
|
||||
|
||||
static IosConfigurations *m_instance = nullptr;
|
||||
|
@@ -650,16 +650,30 @@ Kit *KitManager::registerKit(const std::function<void (Kit *)> &init, Utils::Id
|
||||
|
||||
void KitManager::deregisterKit(Kit *k)
|
||||
{
|
||||
QTC_ASSERT(KitManager::isLoaded(), return);
|
||||
deregisterKits({k});
|
||||
}
|
||||
|
||||
if (!k || !Utils::contains(d->m_kitList, k))
|
||||
return;
|
||||
auto taken = Utils::take(d->m_kitList, k);
|
||||
if (defaultKit() == k) {
|
||||
Kit *newDefault = Utils::findOrDefault(kits(), [](Kit *k) { return k->isValid(); });
|
||||
setDefaultKit(newDefault);
|
||||
void KitManager::deregisterKits(const QList<Kit *> kitList)
|
||||
{
|
||||
QTC_ASSERT(KitManager::isLoaded(), return);
|
||||
std::vector<std::unique_ptr<Kit>> removed; // to keep them alive until the end of the function
|
||||
Kit *newDefault = nullptr;
|
||||
for (Kit *k : kitList) {
|
||||
if (!k)
|
||||
continue;
|
||||
std::optional<std::unique_ptr<Kit>> taken = Utils::take(d->m_kitList, k);
|
||||
if (!taken)
|
||||
continue;
|
||||
removed.push_back(std::move(*taken));
|
||||
if (defaultKit() == k) {
|
||||
newDefault = Utils::findOrDefault(kits(), [](Kit *k) { return k->isValid(); });
|
||||
}
|
||||
}
|
||||
emit instance()->kitRemoved(k);
|
||||
if (newDefault)
|
||||
setDefaultKit(newDefault);
|
||||
|
||||
for (auto it = removed.cbegin(); it != removed.cend(); ++it)
|
||||
emit instance()->kitRemoved(it->get());
|
||||
emit instance()->kitsChanged();
|
||||
}
|
||||
|
||||
|
@@ -153,6 +153,7 @@ public:
|
||||
|
||||
static Kit *registerKit(const std::function<void(Kit *)> &init, Utils::Id id = {});
|
||||
static void deregisterKit(Kit *k);
|
||||
static void deregisterKits(const QList<Kit *> kits);
|
||||
static void setDefaultKit(Kit *k);
|
||||
|
||||
static void saveKits();
|
||||
|
Reference in New Issue
Block a user