aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/classview/classviewmanager.cpp
diff options
context:
space:
mode:
authorJarek Kobus <jaroslaw.kobus@qt.io>2021-03-01 15:01:35 +0100
committerJarek Kobus <jaroslaw.kobus@qt.io>2021-03-17 19:50:28 +0000
commit8fad758f6038875f5219c79fd35e937956e4c890 (patch)
tree11597fa49736b850e9addc9f1cf8717222edbbdb /src/plugins/classview/classviewmanager.cpp
parentced7a2e51ff2d710dd3c18b0259acb595011cc69 (diff)
ClassView: Fix a possible crash on session switch
Don't call SessionManager methods in non-main thread. It's not safe to call SessionManger::projects() or any method of Project class in a non-main thread, as in meantime the Project object may get deleted or the Project object may change in main thread in a not thread-safe way. Instead, prepare the data needed for the parser's thread before, when scheduling a call in a main thread, and pass this data in a safe way. This fixes possible crash in class view, e.g. on session switch. Task-number: QTCREATORBUG-25317 Fixes: QTCREATORBUG-25312 Change-Id: I114aae788aec649d1de3b3d3afdd049ed1e9b2c6 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Diffstat (limited to 'src/plugins/classview/classviewmanager.cpp')
-rw-r--r--src/plugins/classview/classviewmanager.cpp49
1 files changed, 28 insertions, 21 deletions
diff --git a/src/plugins/classview/classviewmanager.cpp b/src/plugins/classview/classviewmanager.cpp
index 7724fbc493..b067ad1cc5 100644
--- a/src/plugins/classview/classviewmanager.cpp
+++ b/src/plugins/classview/classviewmanager.cpp
@@ -44,6 +44,7 @@
#include <QTimer>
using namespace Core;
+using namespace ProjectExplorer;
using namespace Utils;
namespace ClassView {
@@ -94,7 +95,7 @@ public:
ParserTreeItem::ConstPtr m_root;
QTimer m_timer;
- QHash<QString, CPlusPlus::Document::Ptr> m_awaitingDocuments;
+ QSet<FilePath> m_awaitingDocuments;
//! Internal manager state. \sa Manager::state
bool state = false;
@@ -116,7 +117,15 @@ void ManagerPrivate::cancelScheduledUpdate()
void ManagerPrivate::resetParser()
{
cancelScheduledUpdate();
- QMetaObject::invokeMethod(m_parser, &Parser::resetDataToCurrentState, Qt::QueuedConnection);
+
+ QHash<FilePath, QPair<QString, FilePaths>> projectData;
+ for (const Project *project : SessionManager::projects()) {
+ projectData.insert(project->projectFilePath(),
+ qMakePair(project->displayName(), project->files(Project::SourceFiles)));
+ }
+ QMetaObject::invokeMethod(m_parser, [this, projectData]() {
+ m_parser->resetData(projectData);
+ }, Qt::QueuedConnection);
}
/*!
@@ -218,15 +227,26 @@ bool Manager::hasChildren(QStandardItem *item) const
void Manager::initialize()
{
- using ProjectExplorer::SessionManager;
d->m_timer.setSingleShot(true);
// connections to enable/disable navi widget factory
SessionManager *sessionManager = SessionManager::instance();
connect(sessionManager, &SessionManager::projectAdded,
- this, &Manager::onProjectListChanged);
+ this, [this](Project *project) {
+ const FilePath projectPath = project->projectFilePath();
+ const QString projectName = project->displayName();
+ const FilePaths projectFiles = project->files(Project::SourceFiles);
+ QMetaObject::invokeMethod(d->m_parser, [this, projectPath, projectName, projectFiles]() {
+ d->m_parser->addProject(projectPath, projectName, projectFiles);
+ }, Qt::QueuedConnection);
+ });
connect(sessionManager, &SessionManager::projectRemoved,
- this, &Manager::onProjectListChanged);
+ this, [this](Project *project) {
+ const FilePath projectPath = project->projectFilePath();
+ QMetaObject::invokeMethod(d->m_parser, [this, projectPath]() {
+ d->m_parser->removeProject(projectPath);
+ }, Qt::QueuedConnection);
+ });
// connect to the progress manager for signals about Parsing tasks
connect(ProgressManager::instance(), &ProgressManager::taskStarted,
@@ -283,12 +303,12 @@ void Manager::initialize()
if (doc.data() == nullptr)
return;
- d->m_awaitingDocuments.insert(doc->fileName(), doc);
+ d->m_awaitingDocuments.insert(FilePath::fromString(doc->fileName()));
d->m_timer.start(400); // Accumulate multiple requests into one, restarts the timer
});
connect(&d->m_timer, &QTimer::timeout, this, [this]() {
- const QList<CPlusPlus::Document::Ptr> docsToBeUpdated = d->m_awaitingDocuments.values();
+ const QSet<FilePath> docsToBeUpdated = d->m_awaitingDocuments;
d->cancelScheduledUpdate();
if (!state() || d->disableCodeParser) // enabling any of them will trigger the total update
return;
@@ -346,20 +366,7 @@ void Manager::onWidgetVisibilityIsChanged(bool visibility)
if (!visibility)
return;
setState(true);
- onProjectListChanged();
-}
-
-/*!
- Reacts to the project list being changed by updating the navigation pane
- visibility if necessary.
-*/
-
-void Manager::onProjectListChanged()
-{
- // do nothing if Manager is disabled
- if (!state())
- return;
-
+ // TODO: this one may change into getter (when a new class view widget is being shown)
QMetaObject::invokeMethod(d->m_parser, &Parser::requestCurrentState, Qt::QueuedConnection);
}