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 foreach (int breakPointId, breakPointIds(frame->source(), frame->lineNumber()))
52 breakPoints.push_back(t: breakPointId);
53 body.insert(QStringLiteral("breakpoints"), value: breakPoints);
54 script.insert(QStringLiteral("name"), value: frame->source());
55 } break;
56 case QV4Debugger::Throwing:
57 // TODO: complete this!
58 event.insert(QStringLiteral("event"), QStringLiteral("exception"));
59 break;
60 }
61
62 if (!script.isEmpty())
63 body.insert(QStringLiteral("script"), value: script);
64 if (!body.isEmpty())
65 event.insert(QStringLiteral("body"), value: body);
66 m_debugService->send(v4Payload: event);
67}
68
69void QV4DebuggerAgent::addDebugger(QV4Debugger *debugger)
70{
71 Q_ASSERT(!m_debuggers.contains(debugger));
72 m_debuggers << debugger;
73
74 debugger->setBreakOnThrow(m_breakOnThrow);
75
76 for (const BreakPoint &breakPoint : std::as_const(t&: m_breakPoints))
77 if (breakPoint.enabled)
78 debugger->addBreakPoint(fileName: breakPoint.fileName, lineNumber: breakPoint.lineNr, condition: breakPoint.condition);
79
80 connect(sender: debugger, signal: &QObject::destroyed, context: this, slot: &QV4DebuggerAgent::handleDebuggerDeleted);
81 connect(sender: debugger, signal: &QV4Debugger::debuggerPaused, context: this, slot: &QV4DebuggerAgent::debuggerPaused,
82 type: Qt::QueuedConnection);
83}
84
85void QV4DebuggerAgent::removeDebugger(QV4Debugger *debugger)
86{
87 m_debuggers.removeAll(t: debugger);
88 disconnect(sender: debugger, signal: &QObject::destroyed, receiver: this, slot: &QV4DebuggerAgent::handleDebuggerDeleted);
89 disconnect(sender: debugger, signal: &QV4Debugger::debuggerPaused, receiver: this, slot: &QV4DebuggerAgent::debuggerPaused);
90}
91
92const QList<QV4Debugger *> &QV4DebuggerAgent::debuggers()
93{
94 return m_debuggers;
95}
96
97void QV4DebuggerAgent::handleDebuggerDeleted(QObject *debugger)
98{
99 m_debuggers.removeAll(t: static_cast<QV4Debugger *>(debugger));
100}
101
102void QV4DebuggerAgent::pause(QV4Debugger *debugger) const
103{
104 debugger->pause();
105}
106
107void QV4DebuggerAgent::pauseAll() const
108{
109 for (QV4Debugger *debugger : m_debuggers)
110 pause(debugger);
111}
112
113void QV4DebuggerAgent::resumeAll() const
114{
115 for (QV4Debugger *debugger : m_debuggers)
116 if (debugger->state() == QV4Debugger::Paused)
117 debugger->resume(speed: QV4Debugger::FullThrottle);
118}
119
120int QV4DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition)
121{
122 if (enabled) {
123 for (QV4Debugger *debugger : std::as_const(t&: m_debuggers))
124 debugger->addBreakPoint(fileName, lineNumber, condition);
125 }
126
127 const int id = ++m_lastBreakPointId;
128 m_breakPoints.insert(key: id, value: BreakPoint(fileName, lineNumber, enabled, condition));
129 return id;
130}
131
132void QV4DebuggerAgent::removeBreakPoint(int id)
133{
134 BreakPoint breakPoint = m_breakPoints.value(key: id);
135 if (!breakPoint.isValid())
136 return;
137
138 m_breakPoints.remove(key: id);
139
140 if (breakPoint.enabled)
141 for (QV4Debugger *debugger : std::as_const(t&: m_debuggers))
142 debugger->removeBreakPoint(fileName: breakPoint.fileName, lineNumber: breakPoint.lineNr);
143}
144
145void QV4DebuggerAgent::removeAllBreakPoints()
146{
147 for (auto it = m_breakPoints.keyBegin(), end = m_breakPoints.keyEnd(); it != end; ++it)
148 removeBreakPoint(id: *it);
149}
150
151void QV4DebuggerAgent::enableBreakPoint(int id, bool onoff)
152{
153 BreakPoint &breakPoint = m_breakPoints[id];
154 if (!breakPoint.isValid() || breakPoint.enabled == onoff)
155 return;
156 breakPoint.enabled = onoff;
157
158 for (QV4Debugger *debugger : std::as_const(t&: m_debuggers)) {
159 if (onoff)
160 debugger->addBreakPoint(fileName: breakPoint.fileName, lineNumber: breakPoint.lineNr, condition: breakPoint.condition);
161 else
162 debugger->removeBreakPoint(fileName: breakPoint.fileName, lineNumber: breakPoint.lineNr);
163 }
164}
165
166QList<int> QV4DebuggerAgent::breakPointIds(const QString &fileName, int lineNumber) const
167{
168 QList<int> ids;
169
170 for (QHash<int, BreakPoint>::const_iterator i = m_breakPoints.begin(), ei = m_breakPoints.end(); i != ei; ++i)
171 if (i->lineNr == lineNumber && fileName.endsWith(s: i->fileName))
172 ids.push_back(t: i.key());
173
174 return ids;
175}
176
177void QV4DebuggerAgent::setBreakOnThrow(bool onoff)
178{
179 if (onoff != m_breakOnThrow) {
180 m_breakOnThrow = onoff;
181 for (QV4Debugger *debugger : std::as_const(t&: m_debuggers))
182 debugger->setBreakOnThrow(onoff);
183 }
184}
185
186void QV4DebuggerAgent::clearAllPauseRequests()
187{
188 for (QV4Debugger *debugger : std::as_const(t&: m_debuggers))
189 debugger->clearPauseRequest();
190}
191
192QT_END_NAMESPACE
193
194#include "moc_qv4debuggeragent.cpp"
195

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