ProjectExplorer: Fix memory leaks in tree models

Fix widgets being leaked by the ToolChainOptionsPage.
This page created widgets and stored them in the tree node
and never deleted them.

The fix is to put all the widgets into one QStackedWidget, so
that this will clean up once the page is destroyed.

Change-Id: Ic02824a4c52771d8962dc594176077c2e139fb84
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Ivan Donchevskii
2018-07-11 08:25:07 +02:00
parent 263cf4c608
commit 2c0554c187
15 changed files with 38 additions and 33 deletions

View File

@@ -181,9 +181,9 @@ bool AndroidToolChain::operator ==(const ToolChain &tc) const
return m_ndkToolChainVersion == static_cast<const AndroidToolChain &>(tc).m_ndkToolChainVersion; return m_ndkToolChainVersion == static_cast<const AndroidToolChain &>(tc).m_ndkToolChainVersion;
} }
ToolChainConfigWidget *AndroidToolChain::configurationWidget() std::unique_ptr<ToolChainConfigWidget> AndroidToolChain::createConfigurationWidget()
{ {
return new AndroidToolChainConfigWidget(this); return std::make_unique<AndroidToolChainConfigWidget>(this);
} }
FileName AndroidToolChain::suggestedDebugger() const FileName AndroidToolChain::suggestedDebugger() const

View File

@@ -44,7 +44,7 @@ public:
bool operator ==(const ProjectExplorer::ToolChain &) const override; bool operator ==(const ProjectExplorer::ToolChain &) const override;
ProjectExplorer::ToolChainConfigWidget *configurationWidget() override; std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() override;
Utils::FileName suggestedDebugger() const override; Utils::FileName suggestedDebugger() const override;
Utils::FileName suggestedGdbServer() const; Utils::FileName suggestedGdbServer() const;

View File

@@ -136,9 +136,9 @@ IOutputParser *NimToolChain::outputParser() const
return nullptr; return nullptr;
} }
ToolChainConfigWidget *NimToolChain::configurationWidget() std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> NimToolChain::createConfigurationWidget()
{ {
return new NimToolChainConfigWidget(this); return std::make_unique<NimToolChainConfigWidget>(this);
} }
ToolChain *NimToolChain::clone() const ToolChain *NimToolChain::clone() const

View File

@@ -54,7 +54,7 @@ public:
QString compilerVersion() const; QString compilerVersion() const;
void setCompilerCommand(const Utils::FileName &compilerCommand); void setCompilerCommand(const Utils::FileName &compilerCommand);
ProjectExplorer::IOutputParser *outputParser() const final; ProjectExplorer::IOutputParser *outputParser() const final;
ProjectExplorer::ToolChainConfigWidget *configurationWidget() final; std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() final;
ProjectExplorer::ToolChain *clone() const final; ProjectExplorer::ToolChain *clone() const final;
QVariantMap toMap() const final; QVariantMap toMap() const final;

View File

@@ -412,9 +412,9 @@ QList<CustomToolChain::Parser> CustomToolChain::parsers()
return result; return result;
} }
ToolChainConfigWidget *CustomToolChain::configurationWidget() std::unique_ptr<ToolChainConfigWidget> CustomToolChain::createConfigurationWidget()
{ {
return new Internal::CustomToolChainConfigWidget(this); return std::make_unique<Internal::CustomToolChainConfigWidget>(this);
} }
namespace Internal { namespace Internal {

View File

@@ -90,7 +90,7 @@ public:
QVariantMap toMap() const override; QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override; bool fromMap(const QVariantMap &data) override;
ToolChainConfigWidget *configurationWidget() override; std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
bool operator ==(const ToolChain &) const override; bool operator ==(const ToolChain &) const override;

View File

@@ -861,9 +861,9 @@ bool GccToolChain::operator ==(const ToolChain &other) const
&& m_platformLinkerFlags == gccTc->m_platformLinkerFlags; && m_platformLinkerFlags == gccTc->m_platformLinkerFlags;
} }
ToolChainConfigWidget *GccToolChain::configurationWidget() std::unique_ptr<ToolChainConfigWidget> GccToolChain::createConfigurationWidget()
{ {
return new GccToolChainConfigWidget(this); return std::make_unique<GccToolChainConfigWidget>(this);
} }
void GccToolChain::updateSupportedAbis() const void GccToolChain::updateSupportedAbis() const

View File

@@ -158,7 +158,7 @@ public:
QVariantMap toMap() const override; QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override; bool fromMap(const QVariantMap &data) override;
ToolChainConfigWidget *configurationWidget() override; std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
bool operator ==(const ToolChain &) const override; bool operator ==(const ToolChain &) const override;

View File

@@ -764,9 +764,9 @@ bool MsvcToolChain::fromMap(const QVariantMap &data)
} }
ToolChainConfigWidget *MsvcToolChain::configurationWidget() std::unique_ptr<ToolChainConfigWidget> MsvcToolChain::createConfigurationWidget()
{ {
return new MsvcToolChainConfigWidget(this); return std::make_unique<MsvcToolChainConfigWidget>(this);
} }
ToolChain *MsvcToolChain::clone() const ToolChain *MsvcToolChain::clone() const
@@ -1048,9 +1048,9 @@ bool ClangClToolChain::fromMap(const QVariantMap &data)
return true; return true;
} }
ToolChainConfigWidget *ClangClToolChain::configurationWidget() std::unique_ptr<ToolChainConfigWidget> ClangClToolChain::createConfigurationWidget()
{ {
return new ClangClToolChainConfigWidget(this); return std::make_unique<ClangClToolChainConfigWidget>(this);
} }
void ClangClToolChain::resetMsvcToolChain(const MsvcToolChain *base) void ClangClToolChain::resetMsvcToolChain(const MsvcToolChain *base)

View File

@@ -73,7 +73,7 @@ public:
QVariantMap toMap() const override; QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override; bool fromMap(const QVariantMap &data) override;
ToolChainConfigWidget *configurationWidget() override; std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
ToolChain *clone() const override; ToolChain *clone() const override;
@@ -127,7 +127,7 @@ public:
ToolChain *clone() const override; ToolChain *clone() const override;
QVariantMap toMap() const override; QVariantMap toMap() const override;
bool fromMap(const QVariantMap &data) override; bool fromMap(const QVariantMap &data) override;
ToolChainConfigWidget *configurationWidget() override; std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override;
const QList<MsvcToolChain *> &msvcToolchains() const; const QList<MsvcToolChain *> &msvcToolchains() const;
QString clangPath() const { return m_clangPath; } QString clangPath() const { return m_clangPath; }

View File

@@ -146,7 +146,7 @@ public:
virtual bool operator ==(const ToolChain &) const; virtual bool operator ==(const ToolChain &) const;
virtual ToolChainConfigWidget *configurationWidget() = 0; virtual std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() = 0;
virtual bool canClone() const; virtual bool canClone() const;
virtual ToolChain *clone() const = 0; virtual ToolChain *clone() const = 0;

View File

@@ -48,6 +48,7 @@
#include <QMessageBox> #include <QMessageBox>
#include <QPushButton> #include <QPushButton>
#include <QSpacerItem> #include <QSpacerItem>
#include <QStackedWidget>
#include <QTextStream> #include <QTextStream>
#include <QTreeView> #include <QTreeView>
#include <QVBoxLayout> #include <QVBoxLayout>
@@ -60,11 +61,12 @@ namespace Internal {
class ToolChainTreeItem : public TreeItem class ToolChainTreeItem : public TreeItem
{ {
public: public:
ToolChainTreeItem(ToolChain *tc, bool c) : ToolChainTreeItem(QStackedWidget *parentWidget, ToolChain *tc, bool c) :
toolChain(tc), changed(c) toolChain(tc), changed(c)
{ {
widget = tc->configurationWidget(); widget = tc->createConfigurationWidget().release();
if (widget) { if (widget) {
parentWidget->addWidget(widget);
if (tc->isAutoDetected()) if (tc->isAutoDetected())
widget->makeReadOnly(); widget->makeReadOnly();
QObject::connect(widget, &ToolChainConfigWidget::dirty, QObject::connect(widget, &ToolChainConfigWidget::dirty,
@@ -132,9 +134,6 @@ public:
m_model.rootItem()->appendChild(autoRoot); m_model.rootItem()->appendChild(autoRoot);
m_model.rootItem()->appendChild(manualRoot); m_model.rootItem()->appendChild(manualRoot);
foreach (ToolChain *tc, ToolChainManager::toolChains())
insertToolChain(tc);
m_toolChainView = new QTreeView(this); m_toolChainView = new QTreeView(this);
m_toolChainView->setUniformRowHeights(true); m_toolChainView->setUniformRowHeights(true);
m_toolChainView->setSelectionMode(QAbstractItemView::SingleSelection); m_toolChainView->setSelectionMode(QAbstractItemView::SingleSelection);
@@ -174,6 +173,12 @@ public:
m_container->setState(DetailsWidget::NoSummary); m_container->setState(DetailsWidget::NoSummary);
m_container->setVisible(false); m_container->setVisible(false);
m_widgetStack = new QStackedWidget;
m_container->setWidget(m_widgetStack);
foreach (ToolChain *tc, ToolChainManager::toolChains())
insertToolChain(tc);
auto buttonLayout = new QVBoxLayout; auto buttonLayout = new QVBoxLayout;
buttonLayout->setSpacing(6); buttonLayout->setSpacing(6);
buttonLayout->setContentsMargins(0, 0, 0, 0); buttonLayout->setContentsMargins(0, 0, 0, 0);
@@ -234,6 +239,7 @@ public:
QList<ToolChainFactory *> m_factories; QList<ToolChainFactory *> m_factories;
QTreeView *m_toolChainView; QTreeView *m_toolChainView;
DetailsWidget *m_container; DetailsWidget *m_container;
QStackedWidget *m_widgetStack;
QPushButton *m_addButton; QPushButton *m_addButton;
QPushButton *m_cloneButton; QPushButton *m_cloneButton;
QPushButton *m_delButton; QPushButton *m_delButton;
@@ -260,8 +266,9 @@ void ToolChainOptionsWidget::markForRemoval(ToolChainTreeItem *item)
ToolChainTreeItem *ToolChainOptionsWidget::insertToolChain(ToolChain *tc, bool changed) ToolChainTreeItem *ToolChainOptionsWidget::insertToolChain(ToolChain *tc, bool changed)
{ {
StaticTreeItem *parent = parentForToolChain(tc); StaticTreeItem *parent = parentForToolChain(tc);
auto item = new ToolChainTreeItem(tc, changed); auto item = new ToolChainTreeItem(m_widgetStack, tc, changed);
parent->appendChild(item); parent->appendChild(item);
return item; return item;
} }
@@ -308,13 +315,10 @@ StaticTreeItem *ToolChainOptionsWidget::parentForToolChain(ToolChain *tc)
void ToolChainOptionsWidget::toolChainSelectionChanged() void ToolChainOptionsWidget::toolChainSelectionChanged()
{ {
ToolChainTreeItem *item = currentTreeItem(); ToolChainTreeItem *item = currentTreeItem();
QWidget *oldWidget = m_container->takeWidget(); // Prevent deletion.
if (oldWidget)
oldWidget->setVisible(false);
QWidget *currentTcWidget = item ? item->widget : nullptr; QWidget *currentTcWidget = item ? item->widget : nullptr;
m_container->setWidget(currentTcWidget); m_widgetStack->setCurrentWidget(currentTcWidget);
m_container->setVisible(currentTcWidget); m_container->setVisible(currentTcWidget);
updateState(); updateState();
} }

View File

@@ -281,6 +281,7 @@ QList<ToolChain *> ToolChainSettingsAccessor::toolChains(const QVariantMap &data
#include "headerpath.h" #include "headerpath.h"
#include "abi.h" #include "abi.h"
#include "toolchainconfigwidget.h"
#include <QSet> #include <QSet>
#include <QTest> #include <QTest>
@@ -318,7 +319,7 @@ public:
QString makeCommand(const Environment &env) const override { Q_UNUSED(env); return QString("make"); } QString makeCommand(const Environment &env) const override { Q_UNUSED(env); return QString("make"); }
FileName compilerCommand() const override { return Utils::FileName::fromString("/tmp/test/gcc"); } FileName compilerCommand() const override { return Utils::FileName::fromString("/tmp/test/gcc"); }
IOutputParser *outputParser() const override { return nullptr; } IOutputParser *outputParser() const override { return nullptr; }
ToolChainConfigWidget *configurationWidget() override { return nullptr; } std::unique_ptr<ToolChainConfigWidget> createConfigurationWidget() override { return nullptr; }
TTC *clone() const override { return new TTC(*this); } TTC *clone() const override { return new TTC(*this); }
bool operator ==(const ToolChain &other) const override { bool operator ==(const ToolChain &other) const override {
if (!ToolChain::operator==(other)) if (!ToolChain::operator==(other))

View File

@@ -118,9 +118,9 @@ QString QnxToolChain::typeDisplayName() const
return QnxToolChainFactory::tr("QCC"); return QnxToolChainFactory::tr("QCC");
} }
ToolChainConfigWidget *QnxToolChain::configurationWidget() std::unique_ptr<ToolChainConfigWidget> QnxToolChain::createConfigurationWidget()
{ {
return new QnxToolChainConfigWidget(this); return std::make_unique<QnxToolChainConfigWidget>(this);
} }
void QnxToolChain::addToEnvironment(Environment &env) const void QnxToolChain::addToEnvironment(Environment &env) const

View File

@@ -39,7 +39,7 @@ public:
QString typeDisplayName() const override; QString typeDisplayName() const override;
ProjectExplorer::ToolChainConfigWidget *configurationWidget() override; std::unique_ptr<ProjectExplorer::ToolChainConfigWidget> createConfigurationWidget() override;
void addToEnvironment(Utils::Environment &env) const override; void addToEnvironment(Utils::Environment &env) const override;
Utils::FileNameList suggestedMkspecList() const override; Utils::FileNameList suggestedMkspecList() const override;