aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/debugger/dap/cmakedapengine.cpp
blob: aef187eda14bb3a4424d4d0a0a0a09040dfea64b (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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0

#include "cmakedapengine.h"

#include "dapclient.h"

#include <coreplugin/messagemanager.h>

#include <debugger/debuggermainwindow.h>

#include <utils/mimeconstants.h>
#include <utils/mimeutils.h>
#include <utils/temporarydirectory.h>

#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/buildsystem.h>
#include <projectexplorer/projecttree.h>

#include <QDebug>
#include <QLocalSocket>
#include <QLoggingCategory>
#include <QTimer>

using namespace Core;
using namespace Utils;

namespace Debugger::Internal {

class LocalSocketDataProvider : public IDataProvider
{
public:
    LocalSocketDataProvider(const QString &socketName, QObject *parent = nullptr)
        : IDataProvider(parent)
        , m_socketName(socketName)
    {
        connect(&m_socket, &QLocalSocket::connected, this, &IDataProvider::started);
        connect(&m_socket, &QLocalSocket::disconnected, this, &IDataProvider::done);
        connect(&m_socket, &QLocalSocket::readyRead, this, &IDataProvider::readyReadStandardOutput);
        connect(&m_socket,
                &QLocalSocket::errorOccurred,
                this,
                &IDataProvider::readyReadStandardError);
    }

    ~LocalSocketDataProvider() { m_socket.disconnectFromServer(); }

    void start() override { m_socket.connectToServer(m_socketName, QIODevice::ReadWrite); }

    bool isRunning() const override { return m_socket.isOpen(); }
    void writeRaw(const QByteArray &data) override
    {
        if (m_socket.isOpen())
            m_socket.write(data);
    }
    void kill() override
    {
        if (m_socket.isOpen())
            m_socket.disconnectFromServer();
        else {
            m_socket.abort();
            emit done();
        }
    }
    QByteArray readAllStandardOutput() override { return m_socket.readAll(); }
    QString readAllStandardError() override { return QString(); }
    int exitCode() const override { return 0; }
    QString executable() const override { return m_socket.serverName(); }

    QProcess::ExitStatus exitStatus() const override { return QProcess::NormalExit; }
    QProcess::ProcessError error() const override { return QProcess::UnknownError; }
    Utils::ProcessResult result() const override { return ProcessResult::FinishedWithSuccess; }
    QString exitMessage() const override { return QString(); };

private:
    QLocalSocket m_socket;
    const QString m_socketName;
};

class CMakeDapClient : public DapClient
{
public:
    CMakeDapClient(IDataProvider *provider, QObject *parent = nullptr)
        : DapClient(provider, parent)
    {}

    void sendInitialize() override
    {
        postRequest("initialize",
                    QJsonObject{{"clientID", "QtCreator"},
                                {"clientName", "QtCreator"},
                                {"adapterID", "cmake"},
                                {"pathFormat", "path"}});
    }

private:
    const QLoggingCategory &logCategory() override {
        static const QLoggingCategory logCategory = QLoggingCategory("qtc.dbg.dapengine.cmake",
                                                                     QtWarningMsg);
        return logCategory;
    }
};

CMakeDapEngine::CMakeDapEngine()
    : DapEngine()
{
    setObjectName("CmakeDapEngine");
    setDebuggerName("CMake");
    setDebuggerType("DAP");
}

void CMakeDapEngine::setupEngine()
{
    QTC_ASSERT(state() == EngineSetupRequested, qCDebug(logCategory()) << state());

    qCDebug(logCategory()) << "build system name"
                           << ProjectExplorer::activeBuildSystemForCurrentProject()->name();

    IDataProvider *dataProvider;
    if (TemporaryDirectory::masterDirectoryFilePath().osType() == Utils::OsType::OsTypeWindows) {
        dataProvider = new LocalSocketDataProvider("\\\\.\\pipe\\cmake-dap", this);
    } else {
        dataProvider = new LocalSocketDataProvider(TemporaryDirectory::masterDirectoryPath()
                                                       + "/cmake-dap.sock",
                                                   this);
    }
    m_dapClient = new CMakeDapClient(dataProvider, this);
    connectDataGeneratorSignals();

    connect(ProjectExplorer::activeBuildSystemForCurrentProject(),
            &ProjectExplorer::BuildSystem::debuggingStarted,
            this,
            [this] { m_dapClient->dataProvider()->start(); });

    ProjectExplorer::activeBuildSystemForCurrentProject()->requestDebugging();

    QTimer::singleShot(5000, this, [this] {
        if (!m_dapClient->dataProvider()->isRunning()) {
            m_dapClient->dataProvider()->kill();
            MessageManager::writeDisrupting(
                "CMake server is not running. Please check that your CMake is 3.27 or higher.");
            return;
        }
    });
}

bool CMakeDapEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
{
    const auto mimeType = Utils::mimeTypeForFile(bp.fileName);
    return mimeType.matchesName(Utils::Constants::CMAKE_MIMETYPE)
           || mimeType.matchesName(Utils::Constants::CMAKE_PROJECT_MIMETYPE);
}

bool CMakeDapEngine::hasCapability(unsigned cap) const
{
    return cap & (ReloadModuleCapability
                  | BreakConditionCapability
                  | ShowModuleSymbolsCapability
                  /*| AddWatcherCapability*/ // disable while the #25282 bug is not fixed
                  | RunToLineCapability);
}

const QLoggingCategory &CMakeDapEngine::logCategory()
{
    static const QLoggingCategory logCategory = QLoggingCategory("qtc.dbg.dapengine.cmake",
                                                                 QtWarningMsg);
    return logCategory;
}

} // namespace Debugger::Internal