Bug 1582304: Ensure you can add a watchpoint to property within a bucket, prototype, or default properties.
authorMiriam <bmiriam1230@gmail.com>
Thu, 17 Oct 2019 00:45:31 +0000
changeset 497941 ae632346f2a438aeaf52cdec965905a9f3e9030a
parent 497939 20c215afd65de16e3b0427cc98ace7aba69e84c2
child 497942 e7722d02fdabfd0822c18c2e27e2678ab8b15414
push id36702
push userncsoregi@mozilla.com
push dateThu, 17 Oct 2019 15:35:53 +0000
treeherdermozilla-central@a3a8917a857f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1582304
milestone71.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1582304: Ensure you can add a watchpoint to property within a bucket, prototype, or default properties. Differential Revision: https://phabricator.services.mozilla.com/D49496
devtools/client/debugger/packages/devtools-reps/src/object-inspector/actions.js
devtools/client/debugger/packages/devtools-reps/src/object-inspector/utils/node.js
devtools/client/debugger/src/components/SecondaryPanes/Scopes.js
devtools/client/shared/components/reps/reps.js
devtools/server/actors/object.js
--- a/devtools/client/debugger/packages/devtools-reps/src/object-inspector/actions.js
+++ b/devtools/client/debugger/packages/devtools-reps/src/object-inspector/actions.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 // @flow
 
 import type { GripProperties, Node, Props, ReduxAction } from "./types";
 
 const { loadItemProperties } = require("./utils/load-properties");
-const { getPathExpression, getValue } = require("./utils/node");
+const { getPathExpression, getValue, nodeIsBucket } = require("./utils/node");
 const { getLoadedProperties, getActors, getWatchpoints } = require("./reducer");
 
 type Dispatch = ReduxAction => void;
 
 type ThunkArg = {
   getState: () => {},
   dispatch: Dispatch,
 };
@@ -74,17 +74,22 @@ function nodePropertiesLoaded(
 }
 
 /*
  * This action adds a property watchpoint to an object
  */
 function addWatchpoint(item, watchpoint: string) {
   return async function({ dispatch, client }: ThunkArgs) {
     const { parent, name } = item;
-    const object = getValue(parent);
+    let object = getValue(parent);
+
+    if (nodeIsBucket(parent)) {
+      object = getValue(parent.parent);
+    }
+
     if (!object) {
       return;
     }
 
     const path = parent.path;
     const property = name;
     const label = getPathExpression(item);
     const actor = object.actor;
@@ -98,19 +103,25 @@ function addWatchpoint(item, watchpoint:
   };
 }
 
 /*
  * This action removes a property watchpoint from an object
  */
 function removeWatchpoint(item) {
   return async function({ dispatch, client }: ThunkArgs) {
-    const object = getValue(item.parent);
-    const property = item.name;
-    const path = item.parent.path;
+    const { parent, name } = item;
+    let object = getValue(parent);
+
+    if (nodeIsBucket(parent)) {
+      object = getValue(parent.parent);
+    }
+
+    const property = name;
+    const path = parent.path;
     const actor = object.actor;
 
     await client.removeWatchpoint(object, property);
 
     dispatch({
       type: "REMOVE_WATCHPOINT",
       data: { path, property, actor },
     });
--- a/devtools/client/debugger/packages/devtools-reps/src/object-inspector/utils/node.js
+++ b/devtools/client/debugger/packages/devtools-reps/src/object-inspector/utils/node.js
@@ -821,18 +821,20 @@ function getChildren(options: {
 
   return addToCache(makeNodesForProperties(loadedProps, item));
 }
 
 // Builds an expression that resolves to the value of the item in question
 // e.g. `b` in { a: { b: 2 } } resolves to `a.b`
 function getPathExpression(item) {
   if (item && item.parent) {
-    return `${getPathExpression(item.parent)}.${item.name}`;
+    let parent = nodeIsBucket(item.parent) ? item.parent.parent : item.parent;
+    return `${getPathExpression(parent)}.${item.name}`;
   }
+  
   return item.name;
 }
 
 function getParent(item: Node): Node | null {
   return item.parent;
 }
 
 function getNumericalPropertiesCount(item: Node): number {
--- a/devtools/client/debugger/src/components/SecondaryPanes/Scopes.js
+++ b/devtools/client/debugger/src/components/SecondaryPanes/Scopes.js
@@ -114,22 +114,17 @@ class Scopes extends PureComponent<Props
 
   onToggleMapScopes = () => {
     this.props.toggleMapScopes();
   };
 
   onContextMenu = (event: any, item: any) => {
     const { addWatchpoint, removeWatchpoint } = this.props;
 
-    if (
-      !features.watchpoints ||
-      !item.parent ||
-      !item.parent.contents ||
-      !item.contents.configurable
-    ) {
+    if (!features.watchpoints || !item.parent || !item.contents.configurable) {
       return;
     }
 
     if (!item.contents || item.contents.watchpoint) {
       const removeWatchpointLabel = L10N.getStr("watchpoints.removeWatchpoint");
 
       const removeWatchpointItem = {
         id: "node-menu-remove-watchpoint",
--- a/devtools/client/shared/components/reps/reps.js
+++ b/devtools/client/shared/components/reps/reps.js
@@ -2354,17 +2354,18 @@ function getChildren(options) {
 
   return addToCache(makeNodesForProperties(loadedProps, item));
 } // Builds an expression that resolves to the value of the item in question
 // e.g. `b` in { a: { b: 2 } } resolves to `a.b`
 
 
 function getPathExpression(item) {
   if (item && item.parent) {
-    return `${getPathExpression(item.parent)}.${item.name}`;
+    let parent = nodeIsBucket(item.parent) ? item.parent.parent : item.parent;
+    return `${getPathExpression(parent)}.${item.name}`;
   }
 
   return item.name;
 }
 
 function getParent(item) {
   return item.parent;
 }
@@ -7902,17 +7903,18 @@ module.exports = __WEBPACK_EXTERNAL_MODU
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 const {
   loadItemProperties
 } = __webpack_require__(196);
 
 const {
   getPathExpression,
-  getValue
+  getValue,
+  nodeIsBucket
 } = __webpack_require__(114);
 
 const {
   getLoadedProperties,
   getActors,
   getWatchpoints
 } = __webpack_require__(115);
 
@@ -7991,17 +7993,21 @@ function addWatchpoint(item, watchpoint)
   return async function ({
     dispatch,
     client
   }) {
     const {
       parent,
       name
     } = item;
-    const object = getValue(parent);
+    let object = getValue(parent);
+
+    if (nodeIsBucket(parent)) {
+      object = getValue(parent.parent);
+    }
 
     if (!object) {
       return;
     }
 
     const path = parent.path;
     const property = name;
     const label = getPathExpression(item);
@@ -8023,19 +8029,28 @@ function addWatchpoint(item, watchpoint)
  */
 
 
 function removeWatchpoint(item) {
   return async function ({
     dispatch,
     client
   }) {
-    const object = getValue(item.parent);
-    const property = item.name;
-    const path = item.parent.path;
+    const {
+      parent,
+      name
+    } = item;
+    let object = getValue(parent);
+
+    if (nodeIsBucket(parent)) {
+      object = getValue(parent.parent);
+    }
+
+    const property = name;
+    const path = parent.path;
     const actor = object.actor;
     await client.removeWatchpoint(object, property);
     dispatch({
       type: "REMOVE_WATCHPOINT",
       data: {
         path,
         property,
         actor
--- a/devtools/server/actors/object.js
+++ b/devtools/server/actors/object.js
@@ -110,17 +110,19 @@ const proto = {
     // so that it lives for the lifetime of the watchpoint.
     this.thread.threadObjectGrip(this);
 
     if (this._originalDescriptors.has(property)) {
       return;
     }
 
     const obj = this.rawValue();
-    const desc = Object.getOwnPropertyDescriptor(obj, property);
+    const desc =
+      Object.getOwnPropertyDescriptor(obj, property) ||
+      this.obj.getOwnPropertyDescriptor(property);
 
     if (desc.set || desc.get || !desc.configurable) {
       return;
     }
 
     this._originalDescriptors.set(property, { desc, watchpointType });
 
     const pauseAndRespond = type => {