1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qv4debuggeragent.h"
5#include "qv4debugservice.h"
6#include "qv4datacollector.h"
7
8#include <QtCore/qjsonobject.h>
9#include <QtCore/qjsonarray.h>
10
11QT_BEGIN_NAMESPACE
12
13QV4Debugger *QV4DebuggerAgent::pausedDebugger() const
14{
15 for (QV4Debugger *debugger : m_debuggers) {
16 if (debugger->state() == QV4Debugger::Paused)
17 return debugger;
18 }
19 return nullptr;
20}
21
22bool QV4DebuggerAgent::isRunning() const
23{
24 // "running" means none of the engines are paused.
25 return pausedDebugger() == nullptr;
26}
27
28void QV4DebuggerAgent::debuggerPaused(QV4Debugger *debugger, QV4Debugger::PauseReason reason)
29{
30 Q_UNUSED(reason);
31
32 debugger->collector()->clear();
33
34 QJsonObject event, body, script;
35 event.insert(QStringLiteral("type"), QStringLiteral("event"));
36
37 switch (reason) {
38 case QV4Debugger::Step:
39 case QV4Debugger::PauseRequest:
40 case QV4Debugger::BreakPointHit: {
41 event.insert(QStringLiteral("event"), QStringLiteral("break"));
42 QV4::CppStackFrame *frame = debugger->engine()->currentStackFrame;
43 if (!frame)
44 break;
45
46 body.insert(QStringLiteral("invocationText"), value: frame->function());
47 body.insert(QStringLiteral("sourceLine"), value: qAbs(t: frame->lineNumber()) - 1);
48// if (frame->column > 0)
49// body.insert(QStringLiteral("sourceColumn"), frame->column);
50 QJsonArray breakPoints;
51 const QList<int> ids = breakPointIds(fileName: frame->source(), lineNumber: frame->lineNumber());
52 for (int breakPointId : ids)
53 breakPoints.push_back(t: breakPointId);
54 body.insert(QStringLiteral("breakpoints"), value: breakPoints);
55 script.insert(QStringLiteral("name"), value: frame->source());
56 } break;
57 case QV4Debugger::Throwing:
58 // TODO: complete this!
59 event.insert(QStringLiteral("event"), QStringLiteral("exception"));
60 break;
61 }
62
63 if (!script.isEmpty())
64 body.insert(QStringLiteral("script"), value: script);
65 if (!body.isEmpty())
66 event.insert(QStringLiteral("body"), value: body);
67 m_debugService->send(v4Payload: event);
68}
69
70void QV4DebuggerAgent::addDebugger(QV4Debugger *debugger)
71{
72 Q_ASSERT(!m_debuggers.contains(debugger));
73 m_debuggers << debugger;
74
75 debugger->setBreakOnThrow(m_breakOnThrow);
76
77 for (const BreakPoint &breakPoint : std::as_const(t&: m_breakPoints))
78 if (breakPoint.enabled)
79 debugger->addBreakPoint(fileName: breakPoint.fileName, lineNumber: breakPoint.lineNr, condition: breakPoint.condition);
80
81 connect(sender: debugger, signal: &QObject::destroyed, context: this, slot: &QV4DebuggerAgent::handleDebuggerDeleted);
82 connect(sender: debugger, signal: &QV4Debugger::debuggerPaused, context: this, slot: &QV4DebuggerAgent::debuggerPaused,
83 type: Qt::QueuedConnection);
84}
85
86void QV4DebuggerAgent::removeDebugger(QV4Debugger *debugger)
87{
88 m_debuggers.removeAll(t: debugger);
89 disconnect(sender: debugger, signal: &QObject::destroyed, receiver: this, slot: &QV4DebuggerAgent::handleDebuggerDeleted);
90 disconnect(sender: debugger, signal: &QV4Debugger::debuggerPaused, receiver: this, slot: &QV4DebuggerAgent::debuggerPaused);
91}
92
93const QList<QV4Debugger *> &QV4DebuggerAgent::debuggers()
94{
95 return m_debuggers;
96}
97
98void QV4DebuggerAgent::handleDebuggerDeleted(QObject *debugger)
99{
100 m_debuggers.removeAll(t: static_cast<QV4Debugger *>(debugger));
101}
102
103void QV4DebuggerAgent::pause(QV4Debugger *debugger) const
104{
105 debugger->pause();
106}
107
108void QV4DebuggerAgent::pauseAll() const
109{
110 for (QV4Debugger *debugger : m_debuggers)
111 pause(debugger);
112}
113
114void QV4DebuggerAgent::resumeAll() const
115{
116 for (QV4Debugger *debugger : m_debuggers)
117 if (debugger->state() == QV4Debugger::Paused)
118 debugger->resume(speed: QV4Debugger::FullThrottle);
119}
120
121int QV4DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition)
122{
123 if (enabled) {
124 for (QV4Debugger *debugger : std::as_const(t&: m_debuggers))
125 debugger->addBreakPoint(fileName, lineNumber, condition);
126 }
127
128 const int id = ++m_lastBreakPointId;
129 m_breakPoints.insert(key: id, value: BreakPoint(fileName, lineNumber, enabled, condition));
130 return id;
131}
132
133void QV4DebuggerAgent::removeBreakPoint(int id)
134{
135 BreakPoint breakPoint = m_breakPoints.value(key: id);
136 if (!breakPoint.isValid())
137 return;
138
139 m_breakPoints.remove(key: id);
140
141 if (breakPoint.enabled)
142 for (QV4Debugger *debugger : std::as_const(t&: m_debuggers))
143 debugger->removeBreakPoint(fileName: breakPoint.fileName, lineNumber: breakPoint.lineNr);
144}
145
146void QV4DebuggerAgent::removeAllBreakPoints()
147{
148 for (auto it = m_breakPoints.keyBegin(), end = m_breakPoints.keyEnd(); it != end; ++it)
149 removeBreakPoint(id: *it);
150}
151
152void QV4DebuggerAgent::enableBreakPoint(int id, bool onoff)
153{
154 BreakPoint &breakPoint = m_breakPoints[id];
155 if (!breakPoint.isValid() || breakPoint.enabled == onoff)
156 return;
157 breakPoint.enabled = onoff;
158
159 for (QV4Debugger *debugger : std::as_const(t&: m_debuggers)) {
160 if (onoff)
161 debugger->addBreakPoint(fileName: breakPoint.fileName, lineNumber: breakPoint.lineNr, condition: breakPoint.condition);
162 else
163 debugger->removeBreakPoint(fileName: breakPoint.fileName, lineNumber: breakPoint.lineNr);
164 }
165}
166
167QList<int> QV4DebuggerAgent::breakPointIds(const QString &fileName, int lineNumber) const
168{
169 QList<int> ids;
170
171 for (QHash<int, BreakPoint>::const_iterator i = m_breakPoints.begin(), ei = m_breakPoints.end(); i != ei; ++i)
172 if (i->lineNr == lineNumber && fileName.endsWith(s: i->fileName))
173 ids.push_back(t: i.key());
174
175 return ids;
176}
177
178void QV4DebuggerAgent::setBreakOnThrow(bool onoff)
179{
180 if (onoff != m_breakOnThrow) {
181 m_breakOnThrow = onoff;
182 for (QV4Debugger *debugger : std::as_const(t&: m_debuggers))
183 debugger->setBreakOnThrow(onoff);
184 }
185}
186
187void QV4DebuggerAgent::clearAllPauseRequests()
188{
189 for (QV4Debugger *debugger : std::as_const(t&: m_debuggers))
190 debugger->clearPauseRequest();
191}
192
193QT_END_NAMESPACE
194
195#include "moc_qv4debuggeragent.cpp"
196

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtdeclarative/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp