mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Implement Debugger.setBreakpointsActive
Summary: Changelog: [Internal][Added] Support for toggling all breakpoints in Chrome debuggers This implements the Debugger.setBreakpointsActive CDP message, allowing users in Chrome to toggle all exceptions on and off. As with V8/Chrome, setting a breakpoint will automatically re-activate all breakpoints. #utd-hermes-ignore-android Reviewed By: avp Differential Revision: D22825209 fbshipit-source-id: bda2cc59aba04443280bca46126c19bb0cdb58d7
This commit is contained in:
committed by
Facebook GitHub Bot
parent
3c6c5f057a
commit
e1fa53af2e
@@ -351,6 +351,9 @@ folly::Future<debugger::BreakpointInfo> Inspector::setBreakpoint(
|
||||
debugger::SourceLocation loc,
|
||||
folly::Optional<std::string> condition) {
|
||||
auto promise = std::make_shared<folly::Promise<debugger::BreakpointInfo>>();
|
||||
// Automatically re-enable breakpoints since the user presumably wants this
|
||||
// to start triggering.
|
||||
breakpointsActive_ = true;
|
||||
|
||||
executor_->add([this, loc, condition, promise] {
|
||||
setBreakpointOnExecutor(loc, condition, promise);
|
||||
@@ -453,6 +456,14 @@ folly::Future<folly::Unit> Inspector::setPauseOnLoads(
|
||||
return promise->getFuture();
|
||||
};
|
||||
|
||||
folly::Future<folly::Unit> Inspector::setBreakpointsActive(bool active) {
|
||||
// Same logic as setPauseOnLoads.
|
||||
auto promise = std::make_shared<folly::Promise<Unit>>();
|
||||
breakpointsActive_ = active;
|
||||
promise->setValue();
|
||||
return promise->getFuture();
|
||||
};
|
||||
|
||||
bool Inspector::shouldPauseOnThisScriptLoad() {
|
||||
switch (pauseOnLoadMode_) {
|
||||
case None:
|
||||
|
||||
@@ -208,6 +208,12 @@ class Inspector : public facebook::hermes::debugger::EventObserver,
|
||||
*/
|
||||
folly::Future<folly::Unit> setPauseOnLoads(const PauseOnLoadMode mode);
|
||||
|
||||
/**
|
||||
* Set whether breakpoints are active (pause when hit). This does not require
|
||||
* runtime modifications, but returns a future for consistency.
|
||||
*/
|
||||
folly::Future<folly::Unit> setBreakpointsActive(bool active);
|
||||
|
||||
/**
|
||||
* If called during a script load event, return true if we should pause.
|
||||
* Assumed to be called from a script load event where we already hold
|
||||
@@ -326,6 +332,9 @@ class Inspector : public facebook::hermes::debugger::EventObserver,
|
||||
// Whether we should enter a paused state when a script loads.
|
||||
PauseOnLoadMode pauseOnLoadMode_ = PauseOnLoadMode::None;
|
||||
|
||||
// Whether or not we should pause on breakpoints.
|
||||
bool breakpointsActive_ = true;
|
||||
|
||||
// All scripts loaded in to the VM, along with whether we've notified the
|
||||
// client about the script yet.
|
||||
struct LoadedScriptInfo {
|
||||
|
||||
@@ -254,6 +254,12 @@ std::pair<NextStatePtr, CommandPtr> InspectorState::Running::didPause(
|
||||
pendingEvalPromise_->setValue(
|
||||
inspector_.debugger_.getProgramState().getEvalResult());
|
||||
pendingEvalPromise_.reset();
|
||||
} else if (
|
||||
reason == debugger::PauseReason::Breakpoint &&
|
||||
!inspector_.breakpointsActive_) {
|
||||
// We hit a user defined breakpoint, but breakpoints have been deactivated.
|
||||
return std::make_pair<NextStatePtr, CommandPtr>(
|
||||
nullptr, makeContinueCommand());
|
||||
} else /* other cases imply a transition to Pause */ {
|
||||
return std::make_pair<NextStatePtr, CommandPtr>(
|
||||
InspectorState::Paused::make(inspector_), nullptr);
|
||||
|
||||
@@ -81,6 +81,7 @@ class Connection::Impl : public inspector::InspectorObserver,
|
||||
void handle(const m::debugger::ResumeRequest &req) override;
|
||||
void handle(const m::debugger::SetBreakpointRequest &req) override;
|
||||
void handle(const m::debugger::SetBreakpointByUrlRequest &req) override;
|
||||
void handle(const m::debugger::SetBreakpointsActiveRequest &req) override;
|
||||
void handle(
|
||||
const m::debugger::SetInstrumentationBreakpointRequest &req) override;
|
||||
void handle(const m::debugger::SetPauseOnExceptionsRequest &req) override;
|
||||
@@ -659,6 +660,16 @@ void Connection::Impl::handle(
|
||||
.thenError<std::exception>(sendErrorToClient(req.id));
|
||||
}
|
||||
|
||||
void Connection::Impl::handle(
|
||||
const m::debugger::SetBreakpointsActiveRequest &req) {
|
||||
inspector_->setBreakpointsActive(req.active)
|
||||
.via(executor_.get())
|
||||
.thenValue([this, id = req.id](const Unit &unit) {
|
||||
sendResponseToClient(m::makeOkResponse(id));
|
||||
})
|
||||
.thenError<std::exception>(sendErrorToClient(req.id));
|
||||
}
|
||||
|
||||
bool Connection::Impl::isVirtualBreakpointId(const std::string &id) {
|
||||
return id.rfind(kVirtualBreakpointPrefix, 0) == 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
// @generated SignedSource<<f251363b69dd291d2c70e893c3fed04d>>
|
||||
// @generated SignedSource<<addf39d6b92b8dc857e6e5ffe2a441d4>>
|
||||
|
||||
#include "MessageTypes.h"
|
||||
|
||||
@@ -35,6 +35,8 @@ std::unique_ptr<Request> Request::fromJsonThrowOnError(const std::string &str) {
|
||||
{"Debugger.setBreakpoint", makeUnique<debugger::SetBreakpointRequest>},
|
||||
{"Debugger.setBreakpointByUrl",
|
||||
makeUnique<debugger::SetBreakpointByUrlRequest>},
|
||||
{"Debugger.setBreakpointsActive",
|
||||
makeUnique<debugger::SetBreakpointsActiveRequest>},
|
||||
{"Debugger.setInstrumentationBreakpoint",
|
||||
makeUnique<debugger::SetInstrumentationBreakpointRequest>},
|
||||
{"Debugger.setPauseOnExceptions",
|
||||
@@ -509,6 +511,35 @@ void debugger::SetBreakpointByUrlRequest::accept(
|
||||
handler.handle(*this);
|
||||
}
|
||||
|
||||
debugger::SetBreakpointsActiveRequest::SetBreakpointsActiveRequest()
|
||||
: Request("Debugger.setBreakpointsActive") {}
|
||||
|
||||
debugger::SetBreakpointsActiveRequest::SetBreakpointsActiveRequest(
|
||||
const dynamic &obj)
|
||||
: Request("Debugger.setBreakpointsActive") {
|
||||
assign(id, obj, "id");
|
||||
assign(method, obj, "method");
|
||||
|
||||
dynamic params = obj.at("params");
|
||||
assign(active, params, "active");
|
||||
}
|
||||
|
||||
dynamic debugger::SetBreakpointsActiveRequest::toDynamic() const {
|
||||
dynamic params = dynamic::object;
|
||||
put(params, "active", active);
|
||||
|
||||
dynamic obj = dynamic::object;
|
||||
put(obj, "id", id);
|
||||
put(obj, "method", method);
|
||||
put(obj, "params", std::move(params));
|
||||
return obj;
|
||||
}
|
||||
|
||||
void debugger::SetBreakpointsActiveRequest::accept(
|
||||
RequestHandler &handler) const {
|
||||
handler.handle(*this);
|
||||
}
|
||||
|
||||
debugger::SetInstrumentationBreakpointRequest::
|
||||
SetInstrumentationBreakpointRequest()
|
||||
: Request("Debugger.setInstrumentationBreakpoint") {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
// @generated SignedSource<<356df52df2a053b5254f0e039cc36a7b>>
|
||||
// @generated SignedSource<<0563169b47d73a70d7540528f28d1d13>>
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -38,6 +38,7 @@ struct SetBreakpointByUrlRequest;
|
||||
struct SetBreakpointByUrlResponse;
|
||||
struct SetBreakpointRequest;
|
||||
struct SetBreakpointResponse;
|
||||
struct SetBreakpointsActiveRequest;
|
||||
struct SetInstrumentationBreakpointRequest;
|
||||
struct SetInstrumentationBreakpointResponse;
|
||||
struct SetPauseOnExceptionsRequest;
|
||||
@@ -89,6 +90,7 @@ struct RequestHandler {
|
||||
virtual void handle(const debugger::ResumeRequest &req) = 0;
|
||||
virtual void handle(const debugger::SetBreakpointRequest &req) = 0;
|
||||
virtual void handle(const debugger::SetBreakpointByUrlRequest &req) = 0;
|
||||
virtual void handle(const debugger::SetBreakpointsActiveRequest &req) = 0;
|
||||
virtual void handle(
|
||||
const debugger::SetInstrumentationBreakpointRequest &req) = 0;
|
||||
virtual void handle(const debugger::SetPauseOnExceptionsRequest &req) = 0;
|
||||
@@ -116,6 +118,7 @@ struct NoopRequestHandler : public RequestHandler {
|
||||
void handle(const debugger::ResumeRequest &req) override {}
|
||||
void handle(const debugger::SetBreakpointRequest &req) override {}
|
||||
void handle(const debugger::SetBreakpointByUrlRequest &req) override {}
|
||||
void handle(const debugger::SetBreakpointsActiveRequest &req) override {}
|
||||
void handle(
|
||||
const debugger::SetInstrumentationBreakpointRequest &req) override {}
|
||||
void handle(const debugger::SetPauseOnExceptionsRequest &req) override {}
|
||||
@@ -354,6 +357,16 @@ struct debugger::SetBreakpointByUrlRequest : public Request {
|
||||
folly::Optional<std::string> condition;
|
||||
};
|
||||
|
||||
struct debugger::SetBreakpointsActiveRequest : public Request {
|
||||
SetBreakpointsActiveRequest();
|
||||
explicit SetBreakpointsActiveRequest(const folly::dynamic &obj);
|
||||
|
||||
folly::dynamic toDynamic() const override;
|
||||
void accept(RequestHandler &handler) const override;
|
||||
|
||||
bool active{};
|
||||
};
|
||||
|
||||
struct debugger::SetInstrumentationBreakpointRequest : public Request {
|
||||
SetInstrumentationBreakpointRequest();
|
||||
explicit SetInstrumentationBreakpointRequest(const folly::dynamic &obj);
|
||||
|
||||
@@ -750,6 +750,70 @@ TEST(ConnectionTests, testSetBreakpointById) {
|
||||
expectNotification<m::debugger::ResumedNotification>(conn);
|
||||
}
|
||||
|
||||
TEST(ConnectionTests, testActivateBreakpoints) {
|
||||
TestContext context;
|
||||
AsyncHermesRuntime &asyncRuntime = context.runtime();
|
||||
SyncConnection &conn = context.conn();
|
||||
int msgId = 1;
|
||||
|
||||
asyncRuntime.executeScriptAsync(R"(
|
||||
debugger; // line 1
|
||||
x=100 // 2
|
||||
debugger; // 3
|
||||
x=101; // 4
|
||||
)");
|
||||
|
||||
send<m::debugger::EnableRequest>(conn, ++msgId);
|
||||
expectExecutionContextCreated(conn);
|
||||
auto script = expectNotification<m::debugger::ScriptParsedNotification>(conn);
|
||||
|
||||
expectPaused(conn, "other", {{"global", 1, 1}});
|
||||
|
||||
// Set breakpoint #1
|
||||
m::debugger::SetBreakpointRequest req;
|
||||
req.id = ++msgId;
|
||||
req.location.scriptId = script.scriptId;
|
||||
req.location.lineNumber = 2;
|
||||
conn.send(req.toJson());
|
||||
expectResponse<m::debugger::SetBreakpointResponse>(conn, req.id);
|
||||
|
||||
// Set breakpoint #2
|
||||
req.id = ++msgId;
|
||||
req.location.scriptId = script.scriptId;
|
||||
req.location.lineNumber = 4;
|
||||
conn.send(req.toJson());
|
||||
expectResponse<m::debugger::SetBreakpointResponse>(conn, req.id);
|
||||
|
||||
// Disable breakpoints
|
||||
m::debugger::SetBreakpointsActiveRequest activeReq;
|
||||
activeReq.id = ++msgId;
|
||||
activeReq.active = false;
|
||||
conn.send(activeReq.toJson());
|
||||
expectResponse<m::OkResponse>(conn, activeReq.id);
|
||||
|
||||
// Resume
|
||||
send<m::debugger::ResumeRequest>(conn, ++msgId);
|
||||
expectNotification<m::debugger::ResumedNotification>(conn);
|
||||
|
||||
// Expect first breakpoint to be skipped, now hitting line #3
|
||||
expectPaused(conn, "other", {{"global", 3, 1}});
|
||||
|
||||
// Re-enable breakpoints
|
||||
activeReq.id = ++msgId;
|
||||
activeReq.active = true;
|
||||
conn.send(activeReq.toJson());
|
||||
expectResponse<m::OkResponse>(conn, activeReq.id);
|
||||
|
||||
// Resume and expect breakpoints to trigger again
|
||||
send<m::debugger::ResumeRequest>(conn, ++msgId);
|
||||
expectNotification<m::debugger::ResumedNotification>(conn);
|
||||
expectPaused(conn, "other", {{"global", 4, 1}});
|
||||
|
||||
// Continue and exit
|
||||
send<m::debugger::ResumeRequest>(conn, ++msgId);
|
||||
expectNotification<m::debugger::ResumedNotification>(conn);
|
||||
}
|
||||
|
||||
TEST(ConnectionTests, testSetBreakpointByIdWithColumnInIndenting) {
|
||||
TestContext context;
|
||||
AsyncHermesRuntime &asyncRuntime = context.runtime();
|
||||
|
||||
@@ -10,6 +10,7 @@ Debugger.resumed
|
||||
Debugger.scriptParsed
|
||||
Debugger.setBreakpoint
|
||||
Debugger.setBreakpointByUrl
|
||||
Debugger.setBreakpointsActive
|
||||
Debugger.setInstrumentationBreakpoint
|
||||
Debugger.setPauseOnExceptions
|
||||
Debugger.stepInto
|
||||
|
||||
Reference in New Issue
Block a user