Bug 1580585 - Adds set or get watchpoint option. r=jlast

Adds a set or get watchpoint option.

Differential Revision: https://phabricator.services.mozilla.com/D70284

--HG--
extra : moz-landing-system : lando
This commit is contained in:
janelledement 2020-04-15 17:53:52 +00:00
parent a861a4c299
commit 851e55a3df
8 changed files with 191 additions and 3 deletions

View File

@ -1222,4 +1222,4 @@
"6": 6
}
}
}
}

View File

@ -83,6 +83,21 @@ button.remove-get-watchpoint {
background-color: var(--purple-60);
cursor: pointer;
}
button.remove-getorset-watchpoint {
mask: url("resource://devtools/client/debugger/images/webconsole-logpoint.svg")
no-repeat;
display: inline-block;
vertical-align: top;
height: 13px;
width: 15px;
margin: 0 4px 0px 20px;
padding: 0;
border: none;
background-color: var(--yellow-60);
cursor: pointer;
}
.theme-dark button.remove-set-watchpoint:hover,
.theme-light button.remove-set-watchpoint:hover {
background-color: var(--breakpoint-fill);
@ -91,3 +106,8 @@ button.remove-get-watchpoint {
.theme-light button.remove-get-watchpoint:hover {
background-color: var(--purple-60);
}
.theme-dark button.remove-getorset-watchpoint:hover,
.theme-light button.remove-getorset-watchpoint:hover {
background-color: var(--yellow-60);
}

View File

@ -146,6 +146,9 @@ class Scopes extends PureComponent<Props, State> {
const addSetWatchpointLabel = L10N.getStr("watchpoints.setWatchpoint");
const addGetWatchpointLabel = L10N.getStr("watchpoints.getWatchpoint");
const addGetOrSetWatchpointLabel = L10N.getStr(
"watchpoints.getOrSetWatchpoint"
);
const watchpointsSubmenuLabel = L10N.getStr("watchpoints.submenu");
const addSetWatchpointItem = {
@ -162,12 +165,23 @@ class Scopes extends PureComponent<Props, State> {
click: () => addWatchpoint(item, "get"),
};
const addGetOrSetWatchpointItem = {
id: "node-menu-add-get-watchpoint",
label: addGetOrSetWatchpointLabel,
disabled: false,
click: () => addWatchpoint(item, "getorset"),
};
const watchpointsSubmenuItem = {
id: "node-menu-watchpoints",
label: watchpointsSubmenuLabel,
disabled: false,
click: () => addWatchpoint(item, "set"),
submenu: [addSetWatchpointItem, addGetWatchpointItem],
submenu: [
addSetWatchpointItem,
addGetWatchpointItem,
addGetOrSetWatchpointItem,
],
};
const menuItems = [watchpointsSubmenuItem];
@ -191,7 +205,10 @@ class Scopes extends PureComponent<Props, State> {
<button
className={`remove-${watchpoint}-watchpoint`}
title={L10N.getStr("watchpoints.removeWatchpointTooltip")}
onClick={() => removeWatchpoint(item)}
onClick={e => {
e.stopPropagation();
removeWatchpoint(item);
}}
/>
);
};

View File

@ -533,6 +533,10 @@ watchpoints.getWatchpoint=Property get
# watchpoints submenu to add a "set" watchpoint on an object property.
watchpoints.setWatchpoint=Property set
# LOCALIZATION NOTE (watchpoints.getOrSetWatchpoint): This is the text that appears in the
# watchpoints submenu to add a "set" watchpoint on an object property.
watchpoints.getOrSetWatchpoint=Property get or set
# LOCALIZATION NOTE (watchpoints.removeWatchpoint): This is the text that appears in the
# context menu to delete a watchpoint on an object property.
watchpoints.removeWatchpoint=Remove watchpoint

View File

@ -495,6 +495,21 @@ button.remove-get-watchpoint {
background-color: var(--purple-60);
cursor: pointer;
}
button.remove-getorset-watchpoint {
mask: url("resource://devtools/client/debugger/images/webconsole-logpoint.svg")
no-repeat;
display: inline-block;
vertical-align: top;
height: 13px;
width: 15px;
margin: 0 4px 0px 20px;
padding: 0;
border: none;
background-color: var(--yellow-60);
cursor: pointer;
}
.theme-dark button.remove-set-watchpoint:hover,
.theme-light button.remove-set-watchpoint:hover {
background-color: var(--breakpoint-fill);
@ -503,3 +518,8 @@ button.remove-get-watchpoint {
.theme-light button.remove-get-watchpoint:hover {
background-color: var(--purple-60);
}
.theme-dark button.remove-getorset-watchpoint:hover,
.theme-light button.remove-getorset-watchpoint:hover {
background-color: var(--yellow-60);
}

View File

@ -75,6 +75,21 @@ class WatchpointMap {
});
}
if (watchpointType === "getorset") {
objActor.obj.defineProperty(property, {
configurable: desc.configurable,
enumerable: desc.enumerable,
set: objActor.obj.makeDebuggeeValue(v => {
maybeHandlePause("setWatchpoint");
setValue(v);
}),
get: objActor.obj.makeDebuggeeValue(() => {
maybeHandlePause("getWatchpoint");
return getValue();
}),
});
}
return desc;
}

View File

@ -0,0 +1,111 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* eslint-disable no-shadow */
"use strict";
/*
- Adds a 'get or set' watchpoint. Tests that the debugger will pause on both get and set.
*/
add_task(
threadFrontTest(async args => {
await testGetPauseWithGetOrSetWatchpoint(args);
await testSetPauseWithGetOrSetWatchpoint(args);
})
);
async function testGetPauseWithGetOrSetWatchpoint({ threadFront, debuggee }) {
function evaluateTestCode(debuggee) {
/* eslint-disable */
Cu.evalInSandbox(
` // 1
function stopMe(obj) { // 2
debugger; // 3
obj.a + 4; // 4
} //
stopMe({a: 1})`,
debuggee,
"1.8",
"test_watchpoint-05.js"
);
/* eslint-disable */
}
const packet = await executeOnNextTickAndWaitForPause(
() => evaluateTestCode(debuggee),
threadFront
);
info("Test that we paused on the debugger statement");
Assert.equal(packet.frame.where.line, 3);
info("Add get or set watchpoint.");
const args = packet.frame.arguments;
const obj = args[0];
const objClient = threadFront.pauseGrip(obj);
await objClient.addWatchpoint("a", "obj.a", "getorset");
info("Test that watchpoint triggers pause on get.");
const packet2 = await resumeAndWaitForPause(threadFront);
Assert.equal(packet2.frame.where.line, 4);
Assert.equal(packet2.why.type, "getWatchpoint");
Assert.equal(obj.preview.ownProperties.a.value, 1);
await resume(threadFront);
}
async function testSetPauseWithGetOrSetWatchpoint({ threadFront, debuggee, targetFront }) {
async function evaluateJS(input) {
const consoleFront = await targetFront.getFront("console");
const { result } = await consoleFront.evaluateJSAsync(input, {
thread: threadFront.actor,
frameActor: packet.frame.actorID,
});
return result;
}
function evaluateTestCode(debuggee) {
/* eslint-disable */
Cu.evalInSandbox(
` // 1
function stopMe(obj) { // 2
debugger; // 3
obj.a = 2; // 4
} //
stopMe({a: { b: 1 }})`,
debuggee,
"1.8",
"test_watchpoint-05.js"
);
/* eslint-disable */
}
const packet = await executeOnNextTickAndWaitForPause(
() => evaluateTestCode(debuggee),
threadFront
);
info("Test that we paused on the debugger statement");
Assert.equal(packet.frame.where.line, 3);
info("Add get or set watchpoint");
const args = packet.frame.arguments;
const obj = args[0];
const objClient = threadFront.pauseGrip(obj);
await objClient.addWatchpoint("a", "obj.a", "getorset");
let result = await evaluateJS("obj.a");
Assert.equal(result.getGrip().preview.ownProperties.b.value, 1);
result = await evaluateJS("obj.a.b");
Assert.equal(result, 1);
info("Test that watchpoint triggers pause on set");
const packet2 = await resumeAndWaitForPause(threadFront);
Assert.equal(packet2.frame.where.line, 4);
Assert.equal(packet2.why.type, "setWatchpoint");
Assert.equal(obj.preview.ownProperties.a.value.ownPropertyLength, 1);
await resume(threadFront);
}

View File

@ -204,6 +204,7 @@ skip-if = true # breakpoint sliding is not supported bug 1525685
[test_watchpoint-02.js]
[test_watchpoint-03.js]
[test_watchpoint-04.js]
[test_watchpoint-05.js]
[test_breakpoint-actor-map.js]
skip-if = true # tests for breakpoint actors are obsolete bug 1524374
[test_unsafeDereference.js]