1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "debugmodel.h"
6#include "debug.h"
7#include "debuggerglobals.h"
8
9#include <QUuid>
10#include <QString>
11
12#include "stdlib.h"
13
14namespace DEBUG_NAMESPACE {
15DebugModel::DebugModel(dap::optional<dap::array<DebugSession *>> _sessions, QObject *parent)
16 : QObject(parent)
17{
18 if (_sessions) {
19 auto sessionArray = _sessions.value();
20 sessions.insert(sessions.end(), sessionArray.begin(), sessionArray.end());
21 }
22}
23
24dap::array<DebugSession *> DebugModel::getSessions(bool includeInactive)
25{
26 dap::array<DebugSession *> ret;
27
28 std::copy_if(sessions.begin(), sessions.end(), std::back_inserter(ret), [&](const DebugSession *item){
29 return (includeInactive || item->state != State::kInactive);
30 });
31
32 return ret;
33}
34
35dap::optional<DebugSession *> DebugModel::getSession(dap::optional<dap::string> sessionId, bool includeInactive)
36{
37 if (sessionId) {
38 auto filteredSessions = getSessions(includeInactive);
39 for (auto s : filteredSessions) {
40 if (s->getId() == sessionId.value()) {
41 return s;
42 }
43 }
44 }
45 return undefined;
46}
47
48void DebugModel::addSession(DebugSession *session)
49{
50 Q_ASSERT(session);
51 dap::array<DebugSession *> filterdSessions;
52 for (auto s = sessions.begin(); s != sessions.end();) {
53 if ((*s)->getId() == session->getId()) {
54 s = sessions.erase(s);
55 return;
56 }
57 if ((*s)->state == State::kInactive && (*s)->configuration->name == session->configuration->name) {
58 s = sessions.erase(s);
59 return;
60 }
61 ++s;
62 }
63 int i = 1;
64 char szBuf[10] = { 0 };
65 for (auto s = sessions.begin(); s != sessions.end(); ++s) {
66 while ((*s)->getLabel() == session->getLabel()) {
67 sprintf(szBuf, "%d", i);
68 auto newName = session->configuration->name + szBuf;
69 session->setName(newName);
70 memset(szBuf, 0, sizeof(szBuf));
71 }
72 }
73
74 sessions.push_back(session);
75}
76
77void DebugModel::clear()
78{
79 sessions.clear();
80}
81
82void DebugModel::rawUpdate(IRawModelUpdate *data)
83{
84 for (auto it : sessions) {
85 if (it->getId() == data->sessionId) {
86 it->rawUpdate(data);
87 // fire event.
88 }
89 }
90}
91
92void DebugModel::fetchCallStack(Thread &thread)
93{
94 // fetch whole threads.
95 thread.fetchCallStack();
96}
97
98IBreakpoint convertToIBreakpoint(Breakpoint &bp)
99{
100 IBreakpoint ibp;
101 ibp.condition = bp.condition;
102 ibp.hitCondition = bp.hitCondition;
103 ibp.logMessage = bp.logMessage;
104 ibp.verified = bp.verified();
105 ibp.support = bp.supported();
106 ibp.message = bp.message();
107 ibp.sessionsThatVerified = bp.sessionsThatVerified();
108
109 ibp.uri = bp.uri();
110 ibp.lineNumber = bp.lineNumber();
111 ibp.endLineNumber = bp.endLineNumber();
112 ibp.column = bp.column();
113 ibp.endColumn = bp.endColumn();
114 ibp.adapterData = bp.adapterData();
115
116 return ibp;
117}
118
119dap::array<IBreakpoint> DebugModel::getBreakpoints(dap::optional<QUrl> url, dap::optional<int> lineNumber, dap::optional<int> column, dap::optional<bool> enabledOnly)
120{
121 dap::array<IBreakpoint> ret;
122 dap::string uriStr = url ? url->toString().toStdString() : "";
123 for (auto it : breakPoints) {
124 if ((url && it.uri().toString().toStdString() != uriStr)
125 || (lineNumber && lineNumber.value() != it.lineNumber())
126 || (enabledOnly && (!breakpointsActivated || enabledOnly.value() != it.enabled))) {
127 continue;
128 }
129 auto ibp = convertToIBreakpoint(it);
130 ret.push_back(ibp);
131 }
132 return ret;
133}
134
135QMap<QString, dap::array<IBreakpoint>> DebugModel::getAllBreakpoints()
136{
137 QMap<QString, dap::array<IBreakpoint>> allBreakpoints;
138 for (auto it : breakPoints) {
139 auto ibp = convertToIBreakpoint(it);
140 QString path = ibp.uri.path();
141 if (allBreakpoints.contains(path)) {
142 allBreakpoints[path].push_back(ibp);
143 } else {
144 allBreakpoints.insert(path, {ibp});
145 }
146 }
147 return allBreakpoints;
148}
149
150bool DebugModel::areBreakpointsActivated()
151{
152 return breakpointsActivated;
153}
154
155dap::array<IFunctionBreakpoint> DebugModel::getFunctionBreakpoints()
156{
157 return functionBreakpoints;
158}
159
160dap::array<IDataBreakpoint> DebugModel::getDataBreakpoints()
161{
162 return dataBreakpoints;
163}
164
165dap::array<IExceptionBreakpoint> DebugModel::getExceptionBreakpoints()
166{
167 return exceptionBreakpoints;
168}
169
170dap::array<IInstructionBreakpoint> DebugModel::getInstructionBreakpoints()
171{
172 return instructionBreakpoints;
173}
174
175dap::array<IBreakpoint> DebugModel::addBreakpoints(
176 QUrl &uri, dap::array<IBreakpointData> &rawData, bool fireEvent)
177{
178 Q_UNUSED(uri)
179 Q_UNUSED(fireEvent)
180
181 dap::array<IBreakpoint> retBreakpoints;
182 for (auto rawBp : rawData) {
183 Breakpoint bp(uri, rawBp.lineNumber.value(), rawBp.column, rawBp.enabled,
184 rawBp.condition, rawBp.hitCondition, rawBp.logMessage, undefined, rawBp.id.value());
185 auto ibp = convertToIBreakpoint(bp);
186 retBreakpoints.push_back(ibp);
187 breakPoints.push_back(bp);
188 }
189
190 return retBreakpoints;
191}
192
193dap::array<IBreakpoint> DebugModel::removeBreakpoint(const QString &filePath, int lineNumber)
194{
195 for (auto bp = breakPoints.begin(); bp != breakPoints.end(); ) {
196 if (bp->lineNumber() == lineNumber
197 && bp->uri().toString() == filePath) {
198 bp = breakPoints.erase(bp);
199 } else {
200 ++bp;
201 }
202 }
203
204 dap::array<IBreakpoint> retBreakpoints;
205 for (auto bp : breakPoints) {
206 auto ibp = convertToIBreakpoint(bp);
207 retBreakpoints.push_back(ibp);
208 }
209 return retBreakpoints;
210 // fire event.
211}
212
213void DebugModel::updateBreakpoints(std::map<dap::string, IBreakpointUpdateData> &data)
214{
215 Q_UNUSED(data)
216 // dap::array<IBreakpoint> updated;
217 // for (auto bp : breakPoints) {
218 // auto bpData = data.find(bp.Enablement::getId());
219 // if (bpData != data.end()) {
220 // bp.update(bpData->second);
221 // updated.push_back(bp);
222 // }
223 // }
224}
225
226IBreakpointSessionData toBreakpointSessionData(dap::Breakpoint &data, dap::Capabilities &capabilities)
227{
228 Q_UNUSED(data)
229 Q_UNUSED(capabilities)
230 return {};
231}
232
233void DebugModel::setBreakpointSessionData(dap::string &sessionId, const dap::Capabilities &capabilites, dap::optional<std::map<dap::string, dap::Breakpoint>> data)
234{
235 for (auto bp : breakPoints) {
236 if (!data) {
237 bp.setSessionData(sessionId, undefined);
238 } else {
239 auto bpData = data.value().find(bp.getId());
240 if (bpData != data->end()) {
241 // TODO(mozart):write session data.
242 bp.setSessionData(sessionId, undefined);
243 }
244 }
245 }
246}
247
248dap::optional<dap::Breakpoint> DebugModel::getDebugProtocolBreakpoint(
249 dap::string &breakpointId, dap::string &sessionId)
250{
251 for (auto bp : breakPoints) {
252 if (bp.getId() == breakpointId) {
253 return bp.getDebugProtocolBreakpoint(sessionId);
254 }
255 }
256 return undefined;
257}
258
259void DebugModel::enableOrDisableAllBreakpoints(bool enable)
260{
261 for (auto bp : breakPoints) {
262 bp.enabled = enable;
263 }
264}
265
266void DebugModel::setBreakpointsActivated(bool activated)
267{
268 breakpointsActivated = activated;
269 // fire event.
270}
271} // end namespace.
272