forked from qt-creator/qt-creator
ProjectExplorer: Use RAII pattern for parsing start/stop signalling
Change-Id: I13de537140f265db3e3d0ab1cd924d6897cd90c8 Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -112,7 +112,6 @@ Project::RestoreResult AutotoolsProject::fromMap(const QVariantMap &map, QString
|
||||
|
||||
void AutotoolsProject::loadProjectTree()
|
||||
{
|
||||
emitParsingStarted();
|
||||
if (m_makefileParserThread) {
|
||||
// The thread is still busy parsing a previus configuration.
|
||||
// Wait until the thread has been finished and delete it.
|
||||
@@ -125,7 +124,8 @@ void AutotoolsProject::loadProjectTree()
|
||||
}
|
||||
|
||||
// Parse the makefile asynchronously in a thread
|
||||
m_makefileParserThread = new MakefileParserThread(projectFilePath().toString());
|
||||
m_makefileParserThread = new MakefileParserThread(projectFilePath().toString(),
|
||||
guardParsingRun());
|
||||
|
||||
connect(m_makefileParserThread, &MakefileParserThread::started,
|
||||
this, &AutotoolsProject::makefileParsingStarted);
|
||||
@@ -212,8 +212,6 @@ void AutotoolsProject::makefileParsingFinished()
|
||||
|
||||
m_makefileParserThread->deleteLater();
|
||||
m_makefileParserThread = nullptr;
|
||||
|
||||
emitParsingFinished(true);
|
||||
}
|
||||
|
||||
void AutotoolsProject::onFileChanged(const QString &file)
|
||||
|
@@ -31,7 +31,10 @@
|
||||
|
||||
using namespace AutotoolsProjectManager::Internal;
|
||||
|
||||
MakefileParserThread::MakefileParserThread(const QString &makefile) : m_parser(makefile)
|
||||
MakefileParserThread::MakefileParserThread(const QString &makefile,
|
||||
ProjectExplorer::Project::ParseGuard &&guard)
|
||||
: m_parser(makefile)
|
||||
, m_guard(std::move(guard))
|
||||
{
|
||||
connect(&m_parser, &MakefileParser::status,
|
||||
this, &MakefileParserThread::status);
|
||||
@@ -82,7 +85,7 @@ QStringList MakefileParserThread::cxxflags() const
|
||||
bool MakefileParserThread::hasError() const
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
return m_hasError;
|
||||
return !m_guard.isSuccess();
|
||||
}
|
||||
|
||||
bool MakefileParserThread::isCanceled() const
|
||||
@@ -104,7 +107,8 @@ void MakefileParserThread::run()
|
||||
// this prevents long locks if the caller reads a value before the signal
|
||||
// finished() has been emitted.
|
||||
QMutexLocker locker(&m_mutex);
|
||||
m_hasError = !success;
|
||||
if (success)
|
||||
m_guard.markAsSuccess();
|
||||
m_executable = m_parser.executable();
|
||||
m_sources = m_parser.sources();
|
||||
m_makefiles = m_parser.makefiles();
|
||||
|
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "makefileparser.h"
|
||||
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectmacro.h>
|
||||
|
||||
#include <QMutex>
|
||||
@@ -53,7 +54,7 @@ class MakefileParserThread : public QThread
|
||||
using Macros = ProjectExplorer::Macros;
|
||||
|
||||
public:
|
||||
MakefileParserThread(const QString &makefile);
|
||||
MakefileParserThread(const QString &makefile, ProjectExplorer::Project::ParseGuard &&guard);
|
||||
|
||||
/** @see QThread::run() */
|
||||
void run() override;
|
||||
@@ -134,7 +135,6 @@ private:
|
||||
MakefileParser m_parser; ///< Is not accessible outside the thread
|
||||
|
||||
mutable QMutex m_mutex;
|
||||
bool m_hasError = false; ///< Return value for MakefileParserThread::hasError()
|
||||
QString m_executable; ///< Return value for MakefileParserThread::executable()
|
||||
QStringList m_sources; ///< Return value for MakefileParserThread::sources()
|
||||
QStringList m_makefiles; ///< Return value for MakefileParserThread::makefiles()
|
||||
@@ -142,6 +142,8 @@ private:
|
||||
Macros m_macros; ///< Return value for MakefileParserThread::macros()
|
||||
QStringList m_cflags; ///< Return value for MakefileParserThread::cflags()
|
||||
QStringList m_cxxflags; ///< Return value for MakefileParserThread::cxxflags()
|
||||
|
||||
ProjectExplorer::Project::ParseGuard m_guard;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -371,7 +371,7 @@ void CMakeProject::startParsing(int reparseParameters)
|
||||
CMakeBuildConfiguration *bc = activeBc(this);
|
||||
QTC_ASSERT(bc, return );
|
||||
|
||||
emitParsingStarted();
|
||||
m_parseGuard = std::move(guardParsingRun());
|
||||
|
||||
m_waitingForScan = reparseParameters & BuildDirManager::REPARSE_SCAN;
|
||||
m_waitingForParse = true;
|
||||
@@ -466,12 +466,14 @@ void CMakeProject::combineScanAndParse(CMakeBuildConfiguration *bc)
|
||||
if (m_waitingForParse || m_waitingForScan)
|
||||
return;
|
||||
|
||||
if (m_combinedScanAndParseResult)
|
||||
if (m_combinedScanAndParseResult) {
|
||||
m_parseGuard.markAsSuccess();
|
||||
updateProjectData(bc);
|
||||
}
|
||||
|
||||
{
|
||||
TraceTimer parsingDoneTimer(" parsing finished signal");
|
||||
emitParsingFinished(m_combinedScanAndParseResult);
|
||||
m_parseGuard = {};
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -121,6 +121,8 @@ private:
|
||||
QTimer m_delayedParsingTimer;
|
||||
int m_delayedParsingParameters = 0;
|
||||
|
||||
ParseGuard m_parseGuard;
|
||||
|
||||
friend class Internal::CMakeBuildConfiguration;
|
||||
friend class Internal::CMakeBuildSettingsWidget;
|
||||
};
|
||||
|
@@ -450,17 +450,18 @@ void CompilationDatabaseProject::reparseProject()
|
||||
if (m_parser) {
|
||||
QTC_CHECK(isParsing());
|
||||
m_parser->stop();
|
||||
emitParsingFinished(false);
|
||||
}
|
||||
m_parser = new CompilationDbParser(displayName(), projectFilePath(), rootPathFromSettings(),
|
||||
m_mimeBinaryCache, this);
|
||||
m_parser = new CompilationDbParser(displayName(),
|
||||
projectFilePath(),
|
||||
rootPathFromSettings(),
|
||||
m_mimeBinaryCache,
|
||||
guardParsingRun(),
|
||||
this);
|
||||
connect(m_parser, &CompilationDbParser::finished, this, [this](bool success) {
|
||||
if (success)
|
||||
buildTreeAndProjectParts();
|
||||
m_parser = nullptr;
|
||||
emitParsingFinished(success);
|
||||
});
|
||||
emitParsingStarted();
|
||||
m_parser->start();
|
||||
}
|
||||
|
||||
|
@@ -43,14 +43,18 @@ using namespace Utils;
|
||||
namespace CompilationDatabaseProjectManager {
|
||||
namespace Internal {
|
||||
|
||||
CompilationDbParser::CompilationDbParser(const QString &projectName, const FilePath &projectPath,
|
||||
const FilePath &rootPath, MimeBinaryCache &mimeBinaryCache,
|
||||
CompilationDbParser::CompilationDbParser(const QString &projectName,
|
||||
const FilePath &projectPath,
|
||||
const FilePath &rootPath,
|
||||
MimeBinaryCache &mimeBinaryCache,
|
||||
ProjectExplorer::Project::ParseGuard &&guard,
|
||||
QObject *parent)
|
||||
: QObject(parent),
|
||||
m_projectName(projectName),
|
||||
m_projectFilePath(projectPath),
|
||||
m_rootPath(rootPath),
|
||||
m_mimeBinaryCache(mimeBinaryCache)
|
||||
: QObject(parent)
|
||||
, m_projectName(projectName)
|
||||
, m_projectFilePath(projectPath)
|
||||
, m_rootPath(rootPath)
|
||||
, m_mimeBinaryCache(mimeBinaryCache)
|
||||
, m_guard(std::move(guard))
|
||||
{
|
||||
connect(&m_parserWatcher, &QFutureWatcher<void>::finished, this, [this] {
|
||||
m_dbContents = m_parserWatcher.result();
|
||||
@@ -112,6 +116,7 @@ void CompilationDbParser::stop()
|
||||
m_treeScanner->disconnect();
|
||||
m_treeScanner->future().cancel();
|
||||
}
|
||||
m_guard = {};
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
|
@@ -27,6 +27,8 @@
|
||||
|
||||
#include "compilationdatabaseutils.h"
|
||||
|
||||
#include <projectexplorer/project.h>
|
||||
|
||||
#include <utils/fileutils.h>
|
||||
|
||||
#include <QFutureWatcher>
|
||||
@@ -48,15 +50,22 @@ class CompilationDbParser : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CompilationDbParser(const QString &projectName, const Utils::FilePath &projectPath,
|
||||
const Utils::FilePath &rootPath, MimeBinaryCache &mimeBinaryCache,
|
||||
explicit CompilationDbParser(const QString &projectName,
|
||||
const Utils::FilePath &projectPath,
|
||||
const Utils::FilePath &rootPath,
|
||||
MimeBinaryCache &mimeBinaryCache,
|
||||
ProjectExplorer::Project::ParseGuard &&guard,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
QList<ProjectExplorer::FileNode *> scannedFiles() const;
|
||||
DbContents dbContents() const { return m_dbContents; }
|
||||
DbContents dbContents() const
|
||||
{
|
||||
m_guard.markAsSuccess();
|
||||
return m_dbContents;
|
||||
}
|
||||
|
||||
signals:
|
||||
void finished(bool success);
|
||||
@@ -72,6 +81,8 @@ private:
|
||||
ProjectExplorer::TreeScanner *m_treeScanner = nullptr;
|
||||
QFutureWatcher<DbContents> m_parserWatcher;
|
||||
DbContents m_dbContents;
|
||||
|
||||
ProjectExplorer::Project::ParseGuard m_guard;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -409,7 +409,7 @@ FilePath GenericProject::findCommonSourceRoot()
|
||||
|
||||
void GenericProject::refresh(RefreshOptions options)
|
||||
{
|
||||
emitParsingStarted();
|
||||
ParseGuard guard = guardParsingRun();
|
||||
parseProject(options);
|
||||
|
||||
if (options & Files) {
|
||||
@@ -442,7 +442,7 @@ void GenericProject::refresh(RefreshOptions options)
|
||||
|
||||
refreshCppCodeModel();
|
||||
updateDeploymentData();
|
||||
emitParsingFinished(true);
|
||||
guard.markAsSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -135,7 +135,7 @@ void NimProject::collectProjectFiles()
|
||||
|
||||
void NimProject::updateProject()
|
||||
{
|
||||
emitParsingStarted();
|
||||
ParseGuard guard = guardParsingRun();
|
||||
|
||||
auto newRoot = std::make_unique<NimProjectNode>(*this, projectDirectory());
|
||||
|
||||
@@ -147,7 +147,7 @@ void NimProject::updateProject()
|
||||
newRoot->setDisplayName(displayName());
|
||||
setRootProjectNode(std::move(newRoot));
|
||||
|
||||
emitParsingFinished(true);
|
||||
guard.markAsSuccess();
|
||||
}
|
||||
|
||||
Tasks NimProject::projectIssues(const Kit *k) const
|
||||
|
@@ -1014,15 +1014,6 @@ public:
|
||||
setDisplayName(TEST_PROJECT_DISPLAYNAME);
|
||||
}
|
||||
|
||||
void testStartParsing()
|
||||
{
|
||||
emitParsingStarted();
|
||||
}
|
||||
|
||||
void testParsingFinished(bool success) {
|
||||
emitParsingFinished(success);
|
||||
}
|
||||
|
||||
bool needsConfiguration() const final { return false; }
|
||||
};
|
||||
|
||||
@@ -1081,14 +1072,17 @@ void ProjectExplorerPlugin::testProject_parsingSuccess()
|
||||
QSignalSpy startSpy(&project, &Project::parsingStarted);
|
||||
QSignalSpy stopSpy(&project, &Project::parsingFinished);
|
||||
|
||||
project.testStartParsing();
|
||||
{
|
||||
Project::ParseGuard guard = project.guardParsingRun();
|
||||
QCOMPARE(startSpy.count(), 1);
|
||||
QCOMPARE(stopSpy.count(), 0);
|
||||
|
||||
QVERIFY(project.isParsing());
|
||||
QVERIFY(!project.hasParsingData());
|
||||
|
||||
project.testParsingFinished(true);
|
||||
guard.markAsSuccess();
|
||||
}
|
||||
|
||||
QCOMPARE(startSpy.count(), 1);
|
||||
QCOMPARE(stopSpy.count(), 1);
|
||||
QCOMPARE(stopSpy.at(0), {QVariant(true)});
|
||||
@@ -1104,14 +1098,15 @@ void ProjectExplorerPlugin::testProject_parsingFail()
|
||||
QSignalSpy startSpy(&project, &Project::parsingStarted);
|
||||
QSignalSpy stopSpy(&project, &Project::parsingFinished);
|
||||
|
||||
project.testStartParsing();
|
||||
{
|
||||
Project::ParseGuard guard = project.guardParsingRun();
|
||||
QCOMPARE(startSpy.count(), 1);
|
||||
QCOMPARE(stopSpy.count(), 0);
|
||||
|
||||
QVERIFY(project.isParsing());
|
||||
QVERIFY(!project.hasParsingData());
|
||||
}
|
||||
|
||||
project.testParsingFinished(false);
|
||||
QCOMPARE(startSpy.count(), 1);
|
||||
QCOMPARE(stopSpy.count(), 1);
|
||||
QCOMPARE(stopSpy.at(0), {QVariant(false)});
|
||||
|
@@ -204,6 +204,51 @@ public:
|
||||
bool needsInitialExpansion() const;
|
||||
void setNeedsInitialExpansion(bool needsInitialExpansion);
|
||||
|
||||
class ParseGuard
|
||||
{
|
||||
public:
|
||||
ParseGuard()
|
||||
: ParseGuard(nullptr)
|
||||
{}
|
||||
|
||||
~ParseGuard()
|
||||
{
|
||||
if (m_project)
|
||||
m_project->emitParsingFinished(m_success);
|
||||
}
|
||||
|
||||
void markAsSuccess() const { m_success = true; }
|
||||
bool isSuccess() const { return m_success; }
|
||||
bool isNull() const { return !m_project; }
|
||||
|
||||
ParseGuard(const ParseGuard &other) = delete;
|
||||
ParseGuard &operator=(const ParseGuard &other) = delete;
|
||||
ParseGuard(ParseGuard &&other)
|
||||
{
|
||||
std::swap(m_project, other.m_project);
|
||||
std::swap(m_success, other.m_success);
|
||||
}
|
||||
ParseGuard &operator=(ParseGuard &&other)
|
||||
{
|
||||
std::swap(m_project, other.m_project);
|
||||
std::swap(m_success, other.m_success);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
ParseGuard(Project *p)
|
||||
: m_project(p)
|
||||
{
|
||||
if (m_project)
|
||||
m_project->emitParsingStarted();
|
||||
}
|
||||
|
||||
Project *m_project = nullptr;
|
||||
mutable bool m_success = false;
|
||||
|
||||
friend class Project;
|
||||
};
|
||||
|
||||
signals:
|
||||
void displayNameChanged();
|
||||
void fileListChanged();
|
||||
@@ -235,16 +280,12 @@ signals:
|
||||
void rootProjectDirectoryChanged();
|
||||
|
||||
protected:
|
||||
ParseGuard guardParsingRun() { return ParseGuard(this); }
|
||||
|
||||
virtual RestoreResult fromMap(const QVariantMap &map, QString *errorMessage);
|
||||
void createTargetFromMap(const QVariantMap &map, int index);
|
||||
virtual bool setupTarget(Target *t);
|
||||
|
||||
// Helper methods to manage parsing state and signalling
|
||||
// Call in GUI thread before the actual parsing starts
|
||||
void emitParsingStarted();
|
||||
// Call in GUI thread right after the actual parsing is done
|
||||
void emitParsingFinished(bool success);
|
||||
|
||||
void setDisplayName(const QString &name);
|
||||
// Used to pre-check kits in the TargetSetupPage. RequiredKitPredicate
|
||||
// is used to select kits available in the TargetSetupPage
|
||||
@@ -270,6 +311,12 @@ protected:
|
||||
Utils::Environment activeBuildEnvironment() const;
|
||||
|
||||
private:
|
||||
// Helper methods to manage parsing state and signalling
|
||||
// Call in GUI thread before the actual parsing starts
|
||||
void emitParsingStarted();
|
||||
// Call in GUI thread right after the actual parsing is done
|
||||
void emitParsingFinished(bool success);
|
||||
|
||||
void addTarget(std::unique_ptr<Target> &&target);
|
||||
|
||||
void handleSubTreeChanged(FolderNode *node);
|
||||
|
@@ -634,7 +634,7 @@ private:
|
||||
|
||||
void PythonProject::refresh(Target *target)
|
||||
{
|
||||
emitParsingStarted();
|
||||
ParseGuard guard = guardParsingRun();
|
||||
parseProject();
|
||||
|
||||
const QDir baseDir(projectDirectory().toString());
|
||||
@@ -661,7 +661,7 @@ void PythonProject::refresh(Target *target)
|
||||
if (target)
|
||||
target->setApplicationTargets(appTargets);
|
||||
|
||||
emitParsingFinished(true);
|
||||
guard.markAsSuccess();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -463,7 +463,7 @@ bool QbsProject::checkCancelStatus()
|
||||
qCDebug(qbsPmLog) << "Cancel request while parsing, starting re-parse";
|
||||
m_qbsProjectParser->deleteLater();
|
||||
m_qbsProjectParser = nullptr;
|
||||
emitParsingFinished(false);
|
||||
m_guard = {};
|
||||
parseCurrentBuildConfiguration();
|
||||
return true;
|
||||
}
|
||||
@@ -551,7 +551,8 @@ void QbsProject::handleQbsParsingDone(bool success)
|
||||
updateAfterParse();
|
||||
else if (envChanged)
|
||||
updateCppCodeModel();
|
||||
emitParsingFinished(success);
|
||||
m_guard.markAsSuccess();
|
||||
m_guard = {};
|
||||
}
|
||||
|
||||
void QbsProject::rebuildProjectTree()
|
||||
@@ -729,6 +730,8 @@ void QbsProject::configureAsExampleProject()
|
||||
void QbsProject::parse(const QVariantMap &config, const Environment &env, const QString &dir,
|
||||
const QString &configName)
|
||||
{
|
||||
m_guard = guardParsingRun();
|
||||
|
||||
prepareForParsing();
|
||||
QTC_ASSERT(!m_qbsProjectParser, return);
|
||||
|
||||
@@ -736,7 +739,6 @@ void QbsProject::parse(const QVariantMap &config, const Environment &env, const
|
||||
|
||||
QbsManager::updateProfileIfNecessary(activeTarget()->kit());
|
||||
m_qbsProjectParser->parse(config, env, dir, configName);
|
||||
emitParsingStarted();
|
||||
}
|
||||
|
||||
void QbsProject::prepareForParsing()
|
||||
|
@@ -167,6 +167,8 @@ private:
|
||||
bool m_extraCompilersPending = false;
|
||||
|
||||
QHash<QString, Utils::Environment> m_envCache;
|
||||
|
||||
ParseGuard m_guard;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -438,15 +438,15 @@ void QmakeProject::startAsyncTimer(QmakeProFile::AsyncUpdateDelay delay)
|
||||
m_asyncUpdateTimer.stop();
|
||||
m_asyncUpdateTimer.setInterval(qMin(m_asyncUpdateTimer.interval(),
|
||||
delay == QmakeProFile::ParseLater ? UPDATE_INTERVAL : 0));
|
||||
if (!isParsing())
|
||||
emitParsingStarted();
|
||||
|
||||
m_asyncUpdateTimer.start();
|
||||
}
|
||||
|
||||
void QmakeProject::incrementPendingEvaluateFutures()
|
||||
{
|
||||
if (m_pendingEvaluateFuturesCount == 0)
|
||||
m_guard = guardParsingRun();
|
||||
++m_pendingEvaluateFuturesCount;
|
||||
QTC_ASSERT(isParsing(), emitParsingStarted());
|
||||
m_asyncUpdateFutureInterface->setProgressRange(m_asyncUpdateFutureInterface->progressMinimum(),
|
||||
m_asyncUpdateFutureInterface->progressMaximum() + 1);
|
||||
}
|
||||
@@ -486,7 +486,8 @@ void QmakeProject::decrementPendingEvaluateFutures()
|
||||
updateBuildSystemData();
|
||||
if (activeTarget())
|
||||
activeTarget()->updateDefaultDeployConfigurations();
|
||||
emitParsingFinished(true); // Qmake always returns (some) data, even when it failed:-)
|
||||
m_guard.markAsSuccess(); // Qmake always returns (some) data, even when it failed:-)
|
||||
m_guard = {};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -179,6 +179,8 @@ private:
|
||||
|
||||
ProjectExplorer::Target *m_activeTarget = nullptr;
|
||||
mutable ProjectExplorer::ProjectImporter *m_projectImporter = nullptr;
|
||||
|
||||
ParseGuard m_guard;
|
||||
};
|
||||
|
||||
} // namespace QmakeProjectManager
|
||||
|
@@ -152,7 +152,7 @@ void QmlProject::parseProject(RefreshOptions options)
|
||||
|
||||
void QmlProject::refresh(RefreshOptions options)
|
||||
{
|
||||
emitParsingStarted();
|
||||
ParseGuard guard = guardParsingRun();
|
||||
parseProject(options);
|
||||
|
||||
if (options & Files)
|
||||
@@ -170,7 +170,7 @@ void QmlProject::refresh(RefreshOptions options)
|
||||
|
||||
modelManager->updateProjectInfo(projectInfo, this);
|
||||
|
||||
emitParsingFinished(true);
|
||||
guard.markAsSuccess();
|
||||
}
|
||||
|
||||
QString QmlProject::mainFile() const
|
||||
|
Reference in New Issue
Block a user