summaryrefslogtreecommitdiff
path: root/src/plugins/cppeditor/cppprojectupdater.cpp
blob: 6bab2ec3c3ce7d9811f95197b201e757acdd52f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// 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 <coreplugin/progressmanager/taskprogress.h>

#include <projectexplorer/extracompiler.h>

#include <utils/algorithm.h>
#include <utils/asynctask.h>
#include <utils/qtcassert.h>

#include <QFutureInterface>

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<ProjectExplorer::ExtraCompiler *> &extraCompilers)
{
    // Stop previous update.
    cancel();

    const QList<QPointer<ProjectExplorer::ExtraCompiler>> compilers =
        Utils::transform(extraCompilers, [](ExtraCompiler *compiler) {
            return QPointer<ExtraCompiler>(compiler);
        });

    using namespace ProjectExplorer;

    // Run the project info generator in a worker thread and continue if that one is finished.
    const auto infoGenerator = [=](QPromise<ProjectInfo::ConstPtr> &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<UpdateStorage> storage;
    const auto setupInfoGenerator = [=](AsyncTask<ProjectInfo::ConstPtr> &async) {
        async.setConcurrentCallData(infoGenerator);
        async.setFutureSynchronizer(&m_futureSynchronizer);
    };
    const auto onInfoGeneratorDone = [=](const AsyncTask<ProjectInfo::ConstPtr> &async) {
        if (async.isResultAvailable())
            storage->projectInfo = async.result();
    };
    QList<TaskItem> tasks{parallel};
    tasks.append(Async<ProjectInfo::ConstPtr>(setupInfoGenerator, onInfoGeneratorDone));
    for (QPointer<ExtraCompiler> compiler : compilers) {
        if (compiler && compiler->isDirty())
            tasks.append(compiler->compileFileItem());
    }

    const auto onDone = [this, storage, compilers] {
        QList<ExtraCompiler *> extraCompilers;
        QSet<FilePath> compilerFiles;
        for (const QPointer<ExtraCompiler> &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