// Copyright (C) 2017 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "cppprojectupdater.h" #include "cppeditortr.h" #include "cppmodelmanager.h" #include "cppprojectinfogenerator.h" #include "generatedcodemodelsupport.h" #include #include #include #include #include using namespace ProjectExplorer; using namespace Utils; namespace CppEditor { CppProjectUpdater::CppProjectUpdater() = default; CppProjectUpdater::~CppProjectUpdater() = default; void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo) { update(projectUpdateInfo, {}); } void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo, const QList &extraCompilers) { // Stop previous update. cancel(); const QList> compilers = Utils::transform(extraCompilers, [](ExtraCompiler *compiler) { return QPointer(compiler); }); using namespace ProjectExplorer; // Run the project info generator in a worker thread and continue if that one is finished. const auto infoGenerator = [=](QPromise &promise) { ProjectUpdateInfo fullProjectUpdateInfo = projectUpdateInfo; if (fullProjectUpdateInfo.rppGenerator) fullProjectUpdateInfo.rawProjectParts = fullProjectUpdateInfo.rppGenerator(); Internal::ProjectInfoGenerator generator(fullProjectUpdateInfo); promise.addResult(generator.generate(promise)); }; using namespace Tasking; struct UpdateStorage { ProjectInfo::ConstPtr projectInfo = nullptr; }; const TreeStorage storage; const auto setupInfoGenerator = [=](Async &async) { async.setConcurrentCallData(infoGenerator); async.setFutureSynchronizer(&m_futureSynchronizer); }; const auto onInfoGeneratorDone = [=](const Async &async) { if (async.isResultAvailable()) storage->projectInfo = async.result(); }; QList tasks{parallel}; tasks.append(AsyncTask(setupInfoGenerator, onInfoGeneratorDone)); for (QPointer compiler : compilers) { if (compiler && compiler->isDirty()) tasks.append(compiler->compileFileItem()); } const auto onDone = [this, storage, compilers] { QList extraCompilers; QSet compilerFiles; for (const QPointer &compiler : compilers) { if (compiler) { extraCompilers += compiler.data(); compilerFiles += Utils::toSet(compiler->targets()); } } GeneratedCodeModelSupport::update(extraCompilers); auto updateFuture = CppModelManager::instance()->updateProjectInfo(storage->projectInfo, compilerFiles); m_futureSynchronizer.addFuture(updateFuture); m_taskTree.release()->deleteLater(); }; const auto onError = [this] { m_taskTree.release()->deleteLater(); }; const Group root { Storage(storage), Group(tasks), OnGroupDone(onDone), OnGroupError(onError) }; m_taskTree.reset(new TaskTree(root)); auto progress = new Core::TaskProgress(m_taskTree.get()); progress->setDisplayName(Tr::tr("Preparing C++ Code Model")); m_taskTree->start(); } void CppProjectUpdater::cancel() { m_taskTree.reset(); m_futureSynchronizer.cancelAllFutures(); } namespace Internal { CppProjectUpdaterFactory::CppProjectUpdaterFactory() { setObjectName("CppProjectUpdaterFactory"); } CppProjectUpdaterInterface *CppProjectUpdaterFactory::create() { return new CppProjectUpdater; } } // namespace Internal } // namespace CppEditor