DAP: Move to a unified way to handle breakpoints

Rely on SetBreakpoints response instead of breakpoint event.

Change-Id: Iff052a13c442fb1fcd945cf1a80f1354c43c15c5
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Artem Sokolovskii
2023-10-17 16:08:52 +02:00
parent b98be3d5a0
commit 3bf61cc36c
11 changed files with 116 additions and 118 deletions

View File

@@ -1241,7 +1241,7 @@ static bool isAllowedTransition(BreakpointState from, BreakpointState to)
void BreakpointItem::gotoState(BreakpointState target, BreakpointState assumedCurrent) void BreakpointItem::gotoState(BreakpointState target, BreakpointState assumedCurrent)
{ {
QTC_ASSERT(m_state == assumedCurrent, qDebug() << m_state); QTC_ASSERT(m_state == assumedCurrent, qDebug() << target << m_state);
setState(target); setState(target);
} }

View File

@@ -142,6 +142,11 @@ void CMakeDapEngine::setupEngine()
}); });
} }
bool CMakeDapEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
{
return bp.fileName.endsWith(".txt") || bp.fileName.endsWith(".cmake");
}
bool CMakeDapEngine::hasCapability(unsigned cap) const bool CMakeDapEngine::hasCapability(unsigned cap) const
{ {
return cap & (ReloadModuleCapability return cap & (ReloadModuleCapability
@@ -151,32 +156,6 @@ bool CMakeDapEngine::hasCapability(unsigned cap) const
/*| RunToLineCapability*/); // disable while the #25176 bug is not fixed /*| RunToLineCapability*/); // disable while the #25176 bug is not fixed
} }
void CMakeDapEngine::insertBreakpoint(const Breakpoint &bp)
{
DapEngine::insertBreakpoint(bp);
notifyBreakpointInsertOk(bp); // Needed for CMake support issue:25176
}
void CMakeDapEngine::removeBreakpoint(const Breakpoint &bp)
{
DapEngine::removeBreakpoint(bp);
notifyBreakpointRemoveOk(bp); // Needed for CMake support issue:25176
}
void CMakeDapEngine::updateBreakpoint(const Breakpoint &bp)
{
DapEngine::updateBreakpoint(bp);
/* Needed for CMake support issue:25176 */
BreakpointParameters parameters = bp->requestedParameters();
if (parameters.enabled != bp->isEnabled()) {
parameters.pending = false;
bp->setParameters(parameters);
}
notifyBreakpointChangeOk(bp);
/* Needed for CMake support issue:25176 */
}
const QLoggingCategory &CMakeDapEngine::logCategory() const QLoggingCategory &CMakeDapEngine::logCategory()
{ {
static const QLoggingCategory logCategory = QLoggingCategory("qtc.dbg.dapengine.cmake", static const QLoggingCategory logCategory = QLoggingCategory("qtc.dbg.dapengine.cmake",

View File

@@ -15,14 +15,8 @@ public:
private: private:
void setupEngine() override; void setupEngine() override;
/* Needed for CMake support issue:25176 */ bool acceptsBreakpoint(const BreakpointParameters &bp) const override;
void insertBreakpoint(const Breakpoint &bp) override;
void updateBreakpoint(const Breakpoint &bp) override;
void removeBreakpoint(const Breakpoint &bp) override;
/* Needed for CMake support issue:25176 */
bool hasCapability(unsigned cap) const override; bool hasCapability(unsigned cap) const override;
const QLoggingCategory &logCategory() override; const QLoggingCategory &logCategory() override;
}; };

View File

@@ -224,6 +224,8 @@ void DapClient::emitSignals(const QJsonDocument &doc)
type = DapResponseType::Pause; type = DapResponseType::Pause;
} else if (command == "evaluate") { } else if (command == "evaluate") {
type = DapResponseType::Evaluate; type = DapResponseType::Evaluate;
} else if (command == "setBreakpoints") {
type = DapResponseType::SetBreakpoints;
} }
emit responseReady(type, ob); emit responseReady(type, ob);
return; return;

View File

@@ -52,6 +52,7 @@ enum class DapResponseType
StepOver, StepOver,
Pause, Pause,
Evaluate, Evaluate,
SetBreakpoints,
Unknown Unknown
}; };

View File

@@ -325,19 +325,27 @@ void DapEngine::insertBreakpoint(const Breakpoint &bp)
QTC_CHECK(bp->state() == BreakpointInsertionRequested); QTC_CHECK(bp->state() == BreakpointInsertionRequested);
notifyBreakpointInsertProceeding(bp); notifyBreakpointInsertProceeding(bp);
BreakpointParameters parameters = bp->requestedParameters();
if (!parameters.enabled) { // hack for disabling breakpoints
parameters.pending = false;
bp->setParameters(parameters);
notifyBreakpointInsertOk(bp);
return;
}
dapInsertBreakpoint(bp); dapInsertBreakpoint(bp);
} }
void DapEngine::dapInsertBreakpoint(const Breakpoint &bp) void DapEngine::dapInsertBreakpoint(const Breakpoint &bp)
{ {
bp->setResponseId(QString::number(m_nextBreakpointId++));
const BreakpointParameters &params = bp->requestedParameters(); const BreakpointParameters &params = bp->requestedParameters();
QJsonArray breakpoints; QJsonArray breakpoints;
for (const auto &breakpoint : breakHandler()->breakpoints()) { for (const auto &breakpoint : breakHandler()->breakpoints()) {
const BreakpointParameters &bpParams = breakpoint->requestedParameters(); const BreakpointParameters &bpParams = breakpoint->requestedParameters();
QJsonObject jsonBp = createBreakpoint(bpParams); QJsonObject jsonBp = createBreakpoint(bpParams);
if (!jsonBp.isEmpty() && params.fileName.path() == bpParams.fileName.path()) { if (!jsonBp.isEmpty() && params.fileName.path() == bpParams.fileName.path()
&& bpParams.enabled) {
breakpoints.append(jsonBp); breakpoints.append(jsonBp);
} }
} }
@@ -376,7 +384,8 @@ void DapEngine::dapRemoveBreakpoint(const Breakpoint &bp)
QJsonArray breakpoints; QJsonArray breakpoints;
for (const auto &breakpoint : breakHandler()->breakpoints()) { for (const auto &breakpoint : breakHandler()->breakpoints()) {
const BreakpointParameters &bpParams = breakpoint->requestedParameters(); const BreakpointParameters &bpParams = breakpoint->requestedParameters();
if (breakpoint->responseId() != bp->responseId() && params.fileName == bpParams.fileName) { if (breakpoint->responseId() != bp->responseId() && params.fileName == bpParams.fileName
&& bpParams.enabled) {
QJsonObject jsonBp = createBreakpoint(bpParams); QJsonObject jsonBp = createBreakpoint(bpParams);
breakpoints.append(jsonBp); breakpoints.append(jsonBp);
} }
@@ -599,6 +608,9 @@ void DapEngine::handleResponse(DapResponseType type, const QJsonObject &response
case DapResponseType::Evaluate: case DapResponseType::Evaluate:
handleEvaluateResponse(response); handleEvaluateResponse(response);
break; break;
case DapResponseType::SetBreakpoints:
handleBreakpointResponse(response);
break;
default: default:
showMessage("UNKNOWN RESPONSE:" + command); showMessage("UNKNOWN RESPONSE:" + command);
}; };
@@ -693,6 +705,90 @@ void DapEngine::handleEvaluateResponse(const QJsonObject &response)
m_variablesHandler->handleNext(); m_variablesHandler->handleNext();
} }
void DapEngine::handleBreakpointResponse(const QJsonObject &response)
{
const QJsonObject body = response.value("body").toObject();
QJsonArray breakpoints = body.value("breakpoints").toArray();
QHash<QString, QJsonObject> map;
for (QJsonValueRef jsonbp : breakpoints) {
QJsonObject breakpoint = jsonbp.toObject();
QString fileName = breakpoint.value("source").toObject().value("path").toString();
int line = breakpoint.value("line").toInt();
map.insert(fileName + ":" + QString::number(line), breakpoint);
}
const Breakpoints bps = breakHandler()->breakpoints();
for (const Breakpoint &bp : bps) {
BreakpointParameters parameters = bp->requestedParameters();
QString mapKey = parameters.fileName.toString() + ":"
+ QString::number(parameters.textPosition.line);
if (map.find(mapKey) != map.end()) {
if (bp->state() == BreakpointRemoveProceeding) {
notifyBreakpointRemoveFailed(bp);
} else if (bp->state() == BreakpointInsertionProceeding
&& !map.value(mapKey).value("verified").toBool()) {
notifyBreakpointInsertFailed(bp);
} else if (bp->state() == BreakpointInsertionProceeding) {
parameters.pending = false;
bp->setParameters(parameters);
notifyBreakpointInsertOk(bp);
}
if (!bp.isNull())
bp->setResponseId(QString::number(map.value(mapKey).value("id").toInt()));
map.remove(mapKey);
} else {
if (bp->state() == BreakpointRemoveProceeding) {
notifyBreakpointRemoveOk(bp);
}
}
if (!bp.isNull() && bp->state() == BreakpointUpdateProceeding) {
BreakpointParameters parameters = bp->requestedParameters();
if (parameters.enabled != bp->isEnabled()) {
parameters.pending = false;
bp->setParameters(parameters);
notifyBreakpointChangeOk(bp);
continue;
}
}
}
for (const Breakpoint &bp : breakHandler()->breakpoints()) {
if (bp->state() == BreakpointInsertionProceeding) {
if (!bp->isEnabled())
continue;
QString path = bp->requestedParameters().fileName.toString();
int line = bp->requestedParameters().textPosition.line;
QJsonObject jsonBreakpoint;
QString key;
for (QString bpKey : map.keys()) {
QJsonObject breakpoint = map.value(bpKey);
if (path == bp->requestedParameters().fileName.toString()
&& abs(breakpoint.value("line").toInt() - line)
< abs(jsonBreakpoint.value("line").toInt() - line)) {
jsonBreakpoint = breakpoint;
key = bpKey;
}
}
if (!jsonBreakpoint.isEmpty() && jsonBreakpoint.value("verified").toBool()) {
BreakpointParameters parameters = bp->requestedParameters();
parameters.pending = false;
parameters.textPosition.line = jsonBreakpoint.value("line").toInt();
parameters.textPosition.column = jsonBreakpoint.value("column").toInt();
bp->setParameters(parameters);
bp->setResponseId(QString::number(jsonBreakpoint.value("id").toInt()));
notifyBreakpointInsertOk(bp);
map.remove(key);
}
}
}
}
void DapEngine::handleEvent(DapEventType type, const QJsonObject &event) void DapEngine::handleEvent(DapEventType type, const QJsonObject &event)
{ {
const QString eventType = event.value("event").toString(); const QString eventType = event.value("event").toString();
@@ -716,9 +812,6 @@ void DapEngine::handleEvent(DapEventType type, const QJsonObject &event)
if (body.value("reason").toString() == "started" && body.value("threadId").toInt() == 1) if (body.value("reason").toString() == "started" && body.value("threadId").toInt() == 1)
claimInitialBreakpoints(); claimInitialBreakpoints();
break; break;
case DapEventType::DapBreakpoint:
handleBreakpointEvent(event);
break;
case DapEventType::Output: { case DapEventType::Output: {
const QString category = body.value("category").toString(); const QString category = body.value("category").toString();
const QString output = body.value("output").toString(); const QString output = body.value("output").toString();
@@ -761,51 +854,6 @@ void DapEngine::handleStoppedEvent(const QJsonObject &event)
m_dapClient->threads(); m_dapClient->threads();
} }
void DapEngine::handleBreakpointEvent(const QJsonObject &event)
{
const QJsonObject body = event.value("body").toObject();
QJsonObject breakpoint = body.value("breakpoint").toObject();
Breakpoint bp = breakHandler()->findBreakpointByResponseId(
QString::number(breakpoint.value("id").toInt()));
qCDebug(logCategory()) << "breakpoint id :" << breakpoint.value("id").toInt();
if (bp) {
BreakpointParameters parameters = bp->requestedParameters();
if (parameters.enabled != bp->isEnabled()) {
parameters.pending = false;
bp->setParameters(parameters);
notifyBreakpointChangeOk(bp);
return;
}
}
if (body.value("reason").toString() == "new") {
if (breakpoint.value("verified").toBool()) {
notifyBreakpointInsertOk(bp);
const BreakpointParameters &params = bp->requestedParameters();
if (params.oneShot)
continueInferior();
qCDebug(logCategory()) << "breakpoint inserted";
} else {
notifyBreakpointInsertFailed(bp);
qCDebug(logCategory()) << "breakpoint insertion failed";
}
return;
}
if (body.value("reason").toString() == "removed") {
if (breakpoint.value("verified").toBool()) {
notifyBreakpointRemoveOk(bp);
qCDebug(logCategory()) << "breakpoint removed";
} else {
notifyBreakpointRemoveFailed(bp);
qCDebug(logCategory()) << "breakpoint remove failed";
}
return;
}
}
void DapEngine::refreshLocals(const QJsonArray &variables) void DapEngine::refreshLocals(const QJsonArray &variables)
{ {
WatchItem *currentItem = watchHandler()->findItem(m_variablesHandler->currentItem().iname); WatchItem *currentItem = watchHandler()->findItem(m_variablesHandler->currentItem().iname);

View File

@@ -128,9 +128,9 @@ protected:
void handleScopesResponse(const QJsonObject &response); void handleScopesResponse(const QJsonObject &response);
void handleThreadsResponse(const QJsonObject &response); void handleThreadsResponse(const QJsonObject &response);
void handleEvaluateResponse(const QJsonObject &response); void handleEvaluateResponse(const QJsonObject &response);
void handleBreakpointResponse(const QJsonObject &response);
void handleEvent(DapEventType type, const QJsonObject &event); void handleEvent(DapEventType type, const QJsonObject &event);
void handleBreakpointEvent(const QJsonObject &event);
void handleStoppedEvent(const QJsonObject &event); void handleStoppedEvent(const QJsonObject &event);
void updateAll() override; void updateAll() override;

View File

@@ -161,6 +161,11 @@ void GdbDapEngine::setupEngine()
m_dapClient->dataProvider()->start(); m_dapClient->dataProvider()->start();
} }
bool GdbDapEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
{
return bp.fileName.endsWith(".cpp") || bp.fileName.endsWith(".h");
}
const QLoggingCategory &GdbDapEngine::logCategory() const QLoggingCategory &GdbDapEngine::logCategory()
{ {
static const QLoggingCategory logCategory = QLoggingCategory("qtc.dbg.dapengine.gdb", static const QLoggingCategory logCategory = QLoggingCategory("qtc.dbg.dapengine.gdb",

View File

@@ -19,7 +19,7 @@ private:
void handleDapConfigurationDone() override; void handleDapConfigurationDone() override;
bool isLocalAttachEngine() const; bool isLocalAttachEngine() const;
bool acceptsBreakpoint(const BreakpointParameters &bp) const override;
const QLoggingCategory &logCategory() override; const QLoggingCategory &logCategory() override;
}; };

View File

@@ -204,32 +204,6 @@ bool PyDapEngine::acceptsBreakpoint(const BreakpointParameters &bp) const
return bp.fileName.endsWith(".py"); return bp.fileName.endsWith(".py");
} }
void PyDapEngine::insertBreakpoint(const Breakpoint &bp)
{
DapEngine::insertBreakpoint(bp);
notifyBreakpointInsertOk(bp); // Needed for Python support issue:1386
}
void PyDapEngine::removeBreakpoint(const Breakpoint &bp)
{
DapEngine::removeBreakpoint(bp);
notifyBreakpointRemoveOk(bp); // Needed for Python support issue:1386
}
void PyDapEngine::updateBreakpoint(const Breakpoint &bp)
{
DapEngine::updateBreakpoint(bp);
/* Needed for Python support issue:1386 */
BreakpointParameters parameters = bp->requestedParameters();
if (parameters.enabled != bp->isEnabled()) {
parameters.pending = false;
bp->setParameters(parameters);
}
notifyBreakpointChangeOk(bp);
/* Needed for Python support issue:1386 */
}
bool PyDapEngine::isLocalAttachEngine() const bool PyDapEngine::isLocalAttachEngine() const
{ {
return runParameters().startMode == AttachToLocalProcess; return runParameters().startMode == AttachToLocalProcess;

View File

@@ -20,11 +20,6 @@ private:
bool isLocalAttachEngine() const; bool isLocalAttachEngine() const;
bool acceptsBreakpoint(const BreakpointParameters &bp) const override; bool acceptsBreakpoint(const BreakpointParameters &bp) const override;
/* Needed for Python support issue:1386 */
void insertBreakpoint(const Breakpoint &bp) override;
void updateBreakpoint(const Breakpoint &bp) override;
void removeBreakpoint(const Breakpoint &bp) override;
/* Needed for Python support issue:1386 */
const QLoggingCategory &logCategory() override; const QLoggingCategory &logCategory() override;