diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 2ec4e68e6c3..71fac0757cf 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -630,8 +630,7 @@ void CMakeBuildSystem::updateProjectData() { qDeleteAll(m_extraCompilers); m_extraCompilers = findExtraCompilers(); - CppTools::GeneratedCodeModelSupport::update(m_extraCompilers); - qCDebug(cmakeBuildSystemLog) << "Extra compilers updated."; + qCDebug(cmakeBuildSystemLog) << "Extra compilers created."; } QtSupport::CppKitInfo kitInfo(kit()); @@ -658,7 +657,8 @@ void CMakeBuildSystem::updateProjectData() } } - m_cppCodeModelUpdater->update({p, kitInfo, cmakeBuildConfiguration()->environment(), rpps}); + m_cppCodeModelUpdater->update({p, kitInfo, cmakeBuildConfiguration()->environment(), rpps}, + m_extraCompilers); } { const bool mergedHeaderPathsAndQmlImportPaths = kit()->value( diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index f92248b2228..2366b5d4daf 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -1145,7 +1145,8 @@ void CppModelManager::updateCppEditorDocuments(bool projectsUpdated) const } } -QFuture CppModelManager::updateProjectInfo(const ProjectInfo &newProjectInfo) +QFuture CppModelManager::updateProjectInfo(const ProjectInfo &newProjectInfo, + const QSet &additionalFiles) { if (!newProjectInfo.isValid()) return QFuture(); @@ -1236,6 +1237,7 @@ QFuture CppModelManager::updateProjectInfo(const ProjectInfo &newProjectIn // resolved includes that we could rely on. updateCppEditorDocuments(/*projectsUpdated = */ true); + filesToReindex.unite(additionalFiles); // Trigger reindexing const QFuture indexingFuture = updateSourceFiles(filesToReindex, ForcedProgressNotification); diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index 402f37bee6d..81e8ec3710b 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -116,7 +116,8 @@ public: QList projectInfos() const; ProjectInfo projectInfo(ProjectExplorer::Project *project) const; - QFuture updateProjectInfo(const ProjectInfo &newProjectInfo); + QFuture updateProjectInfo(const ProjectInfo &newProjectInfo, + const QSet &additionalFiles = {}); /// \return The project part with the given project file ProjectPart::Ptr projectPartForId(const QString &projectPartId) const override; diff --git a/src/plugins/cpptools/cppprojectupdater.cpp b/src/plugins/cpptools/cppprojectupdater.cpp index 794fd7abe7f..f34628af51a 100644 --- a/src/plugins/cpptools/cppprojectupdater.cpp +++ b/src/plugins/cpptools/cppprojectupdater.cpp @@ -27,14 +27,21 @@ #include "cppmodelmanager.h" #include "cppprojectinfogenerator.h" +#include "generatedcodemodelsupport.h" + +#include #include +#include +#include #include #include #include +using namespace ProjectExplorer; + namespace CppTools { CppProjectUpdater::CppProjectUpdater() @@ -46,11 +53,25 @@ CppProjectUpdater::CppProjectUpdater() m_futureSynchronizer.setCancelOnWait(true); } -void CppProjectUpdater::update(const ProjectExplorer::ProjectUpdateInfo &projectUpdateInfo) +CppProjectUpdater::~CppProjectUpdater() +{ + cancel(); +} + +void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo) +{ + update(projectUpdateInfo, {}); +} + +void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo, + const QList &extraCompilers) { // Stop previous update. cancel(); + m_extraCompilers = Utils::transform(extraCompilers, [](ExtraCompiler *compiler) { + return QPointer(compiler); + }); m_projectUpdateInfo = projectUpdateInfo; // Ensure that we do not operate on a deleted toolchain. @@ -68,15 +89,52 @@ void CppProjectUpdater::update(const ProjectExplorer::ProjectUpdateInfo &project }); m_generateFutureWatcher.setFuture(generateFuture); m_futureSynchronizer.addFuture(generateFuture); + + // extra compilers + for (QPointer compiler : qAsConst(m_extraCompilers)) { + if (compiler->isDirty()) { + auto watcher = new QFutureWatcher; + // queued connection to delay after the extra compiler updated its result contents, + // which is also done in the main thread when compiler->run() finished + connect(watcher, &QFutureWatcherBase::finished, + this, [this, watcher] { + m_projectUpdateFutureInterface->setProgressValue( + m_projectUpdateFutureInterface->progressValue() + 1); + m_extraCompilersFutureWatchers.remove(watcher); + watcher->deleteLater(); + if (!watcher->isCanceled()) + checkForExtraCompilersFinished(); + }, + Qt::QueuedConnection); + m_extraCompilersFutureWatchers += watcher; + watcher->setFuture(QFuture(compiler->run())); + m_futureSynchronizer.addFuture(watcher->future()); + } + } + + m_projectUpdateFutureInterface.reset(new QFutureInterface); + m_projectUpdateFutureInterface->setProgressRange(0, m_extraCompilersFutureWatchers.size() + + 1 /*generateFuture*/); + m_projectUpdateFutureInterface->setProgressValue(0); + m_projectUpdateFutureInterface->reportStarted(); + Core::ProgressManager::addTask(m_projectUpdateFutureInterface->future(), + tr("Preparing C++ Code Model"), + "CppProjectUpdater"); } void CppProjectUpdater::cancel() { + if (m_projectUpdateFutureInterface && m_projectUpdateFutureInterface->isRunning()) + m_projectUpdateFutureInterface->reportFinished(); m_generateFutureWatcher.setFuture({}); + m_isProjectInfoGenerated = false; + qDeleteAll(m_extraCompilersFutureWatchers); + m_extraCompilersFutureWatchers.clear(); + m_extraCompilers.clear(); m_futureSynchronizer.cancelAllFutures(); } -void CppProjectUpdater::onToolChainRemoved(ProjectExplorer::ToolChain *t) +void CppProjectUpdater::onToolChainRemoved(ToolChain *t) { QTC_ASSERT(t, return); if (t == m_projectUpdateInfo.cToolChain || t == m_projectUpdateInfo.cxxToolChain) @@ -93,8 +151,33 @@ void CppProjectUpdater::onProjectInfoGenerated() if (m_generateFutureWatcher.isCanceled() || m_generateFutureWatcher.future().resultCount() < 1) return; - auto updateFuture = CppModelManager::instance()->updateProjectInfo( - m_generateFutureWatcher.result()); + m_projectUpdateFutureInterface->setProgressValue(m_projectUpdateFutureInterface->progressValue() + + 1); + m_isProjectInfoGenerated = true; + checkForExtraCompilersFinished(); +} + +void CppProjectUpdater::checkForExtraCompilersFinished() +{ + if (!m_extraCompilersFutureWatchers.isEmpty() || !m_isProjectInfoGenerated) + return; // still need to wait + + m_projectUpdateFutureInterface->reportFinished(); + m_projectUpdateFutureInterface.reset(); + + QList extraCompilers; + QSet compilerFiles; + for (const QPointer &compiler : qAsConst(m_extraCompilers)) { + if (compiler) { + extraCompilers += compiler.data(); + compilerFiles += Utils::transform(compiler->targets(), &Utils::FilePath::toString); + } + } + GeneratedCodeModelSupport::update(extraCompilers); + m_extraCompilers.clear(); + + auto updateFuture = CppModelManager::instance() + ->updateProjectInfo(m_generateFutureWatcher.result(), compilerFiles); m_futureSynchronizer.addFuture(updateFuture); } diff --git a/src/plugins/cpptools/cppprojectupdater.h b/src/plugins/cpptools/cppprojectupdater.h index 6b994871ef9..c356ab63d19 100644 --- a/src/plugins/cpptools/cppprojectupdater.h +++ b/src/plugins/cpptools/cppprojectupdater.h @@ -29,6 +29,7 @@ #include "cpptools_global.h" #include "projectinfo.h" +#include #include #include @@ -54,18 +55,26 @@ class CPPTOOLS_EXPORT CppProjectUpdater final : public QObject, public CppProjec public: CppProjectUpdater(); + ~CppProjectUpdater() override; void update(const ProjectExplorer::ProjectUpdateInfo &projectUpdateInfo) override; + void update(const ProjectExplorer::ProjectUpdateInfo &projectUpdateInfo, + const QList &extraCompilers); void cancel() override; private: void onToolChainRemoved(ProjectExplorer::ToolChain *); void onProjectInfoGenerated(); + void checkForExtraCompilersFinished(); private: ProjectExplorer::ProjectUpdateInfo m_projectUpdateInfo; + QList> m_extraCompilers; QFutureWatcher m_generateFutureWatcher; + bool m_isProjectInfoGenerated = false; + QSet *> m_extraCompilersFutureWatchers; + std::unique_ptr> m_projectUpdateFutureInterface; Utils::FutureSynchronizer m_futureSynchronizer; }; diff --git a/src/plugins/projectexplorer/extracompiler.cpp b/src/plugins/projectexplorer/extracompiler.cpp index 6dd653774ec..893997de3fe 100644 --- a/src/plugins/projectexplorer/extracompiler.cpp +++ b/src/plugins/projectexplorer/extracompiler.cpp @@ -123,11 +123,6 @@ ExtraCompiler::ExtraCompiler(const Project *project, const Utils::FilePath &sour if (file.open(QFile::ReadOnly | QFile::Text)) setContent(target, file.readAll()); } - - if (d->dirty) { - d->dirty = false; - QTimer::singleShot(0, this, [this]() { run(d->source); }); // delay till available. - } } ExtraCompiler::~ExtraCompiler() = default; @@ -173,6 +168,11 @@ QThreadPool *ExtraCompiler::extraCompilerThreadPool() return s_extraCompilerThreadPool(); } +bool ExtraCompiler::isDirty() const +{ + return d->dirty; +} + void ExtraCompiler::onTargetsBuilt(Project *project) { if (project != d->project || BuildManager::isBuilding(project)) @@ -346,15 +346,16 @@ void ProcessExtraCompiler::run(const QByteArray &sourceContents) runImpl(contents); } -void ProcessExtraCompiler::run(const Utils::FilePath &fileName) +QFuture ProcessExtraCompiler::run() { + const Utils::FilePath fileName = source(); ContentProvider contents = [fileName]() { QFile file(fileName.toString()); if (!file.open(QFile::ReadOnly | QFile::Text)) return QByteArray(); return file.readAll(); }; - runImpl(contents); + return runImpl(contents); } Utils::FilePath ProcessExtraCompiler::workingDirectory() const @@ -379,7 +380,7 @@ Tasks ProcessExtraCompiler::parseIssues(const QByteArray &stdErr) return {}; } -void ProcessExtraCompiler::runImpl(const ContentProvider &provider) +QFuture ProcessExtraCompiler::runImpl(const ContentProvider &provider) { if (m_watcher) delete m_watcher; @@ -392,6 +393,7 @@ void ProcessExtraCompiler::runImpl(const ContentProvider &provider) &ProcessExtraCompiler::runInThread, this, command(), workingDirectory(), arguments(), provider, buildEnvironment())); + return m_watcher->future(); } void ProcessExtraCompiler::runInThread( diff --git a/src/plugins/projectexplorer/extracompiler.h b/src/plugins/projectexplorer/extracompiler.h index 5c0854a3b4b..e38a5900a0d 100644 --- a/src/plugins/projectexplorer/extracompiler.h +++ b/src/plugins/projectexplorer/extracompiler.h @@ -80,6 +80,9 @@ public: static QThreadPool *extraCompilerThreadPool(); + virtual QFuture run() = 0; + bool isDirty() const; + signals: void contentsChanged(const Utils::FilePath &file); @@ -94,7 +97,6 @@ private: void setDirty(); // This method may not block! virtual void run(const QByteArray &sourceContent) = 0; - virtual void run(const Utils::FilePath &file) = 0; const std::unique_ptr d; }; @@ -115,7 +117,7 @@ protected: // * prepareToRun returns true // * The process is not yet running void run(const QByteArray &sourceContents) override; - void run(const Utils::FilePath &fileName) override; + QFuture run() override; // Information about the process to run: virtual Utils::FilePath workingDirectory() const; @@ -133,7 +135,7 @@ protected: private: using ContentProvider = std::function; - void runImpl(const ContentProvider &sourceContents); + QFuture runImpl(const ContentProvider &sourceContents); void runInThread(QFutureInterface &futureInterface, const Utils::FilePath &cmd, const Utils::FilePath &workDir, const QStringList &args, const ContentProvider &provider, diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index dcf5552468d..1de06cedaf1 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -193,6 +193,10 @@ QbsBuildSystem::QbsBuildSystem(QbsBuildConfiguration *bc) } } CppTools::GeneratedCodeModelSupport::update(m_extraCompilers); + for (ExtraCompiler *compiler : m_extraCompilers) { + if (compiler->isDirty()) + compiler->run(); + } m_sourcesForGeneratedFiles.clear(); }); connect(m_session, &QbsSession::errorOccurred, this, [](QbsSession::Error e) { diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index a1ff1f21f11..acb1c14e1f4 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -399,8 +399,7 @@ void QmakeBuildSystem::updateCppCodeModel() rpps.append(rpp); } - CppTools::GeneratedCodeModelSupport::update(generators); - m_cppCodeModelUpdater->update({project(), kitInfo, activeParseEnvironment(), rpps}); + m_cppCodeModelUpdater->update({project(), kitInfo, activeParseEnvironment(), rpps}, generators); } void QmakeBuildSystem::updateQmlJSCodeModel()