Web Inspector: ES6: Show Symbol properties on Objects
authorjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Apr 2015 21:28:57 +0000 (21:28 +0000)
committerjoepeck@webkit.org <joepeck@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 7 Apr 2015 21:28:57 +0000 (21:28 +0000)
https://bugs.webkit.org/show_bug.cgi?id=141279

Reviewed by Timothy Hatcher.

Source/JavaScriptCore:

* inspector/protocol/Runtime.json:
Give PropertyDescriptor a reference to the Symbol RemoteObject
if the property is a symbol property.

* inspector/InjectedScriptSource.js:
Enumerate symbol properties on objects.

Source/WebInspectorUI:

* Localizations/en.lproj/localizedStrings.js:
* UserInterface/Models/PropertyDescriptor.js:
(WebInspector.PropertyDescriptor.get symbol):

* UserInterface/Protocol/RemoteObject.js:
(WebInspector.RemoteObject.wrappedCallback):
Update new PropertyDescriptor call site.

* UserInterface/Views/ObjectTreeBaseTreeElement.js:
(WebInspector.ObjectTreeBaseTreeElement._logSymbolProperty):
Provide a context menu for rows with Symbol properties to log
the Symbol property, and therefore get a reference to it.

* UserInterface/Views/ObjectTreeView.js:
(WebInspector.ObjectTreeView.comparePropertyDescriptors):
Better handle symbol properties in sorting.

* UserInterface/Views/TypePropertiesSection.js:
(WebInspector.TypePropertiesSection.PropertyComparator):
Return better value when values are equal.

LayoutTests:

* inspector/model/remote-object-expected.txt:
* inspector/model/remote-object-get-properties-expected.txt:
* inspector/model/remote-object-get-properties.html:
* inspector/model/remote-object.html:
Update tests to include objects with Symbol properties.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@182493 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
LayoutTests/ChangeLog
LayoutTests/inspector/model/remote-object-expected.txt
LayoutTests/inspector/model/remote-object-get-properties-expected.txt
LayoutTests/inspector/model/remote-object-get-properties.html
LayoutTests/inspector/model/remote-object.html
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/inspector/InjectedScriptSource.js
Source/JavaScriptCore/inspector/protocol/Runtime.json
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js
Source/WebInspectorUI/UserInterface/Models/PropertyDescriptor.js
Source/WebInspectorUI/UserInterface/Protocol/RemoteObject.js
Source/WebInspectorUI/UserInterface/Views/ObjectTreeBaseTreeElement.js
Source/WebInspectorUI/UserInterface/Views/ObjectTreeView.js
Source/WebInspectorUI/UserInterface/Views/TypePropertiesSection.js

index 8381451..c9975bf 100644 (file)
@@ -1,3 +1,16 @@
+2015-04-07  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: ES6: Show Symbol properties on Objects
+        https://bugs.webkit.org/show_bug.cgi?id=141279
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/model/remote-object-expected.txt:
+        * inspector/model/remote-object-get-properties-expected.txt:
+        * inspector/model/remote-object-get-properties.html:
+        * inspector/model/remote-object.html:
+        Update tests to include objects with Symbol properties.
+
 2015-02-25  Sergio Villar Senin  <svillar@igalia.com>
 
         [CSS Grid Layout] Update track sizes after distributing extra space
index e701e64..fb4a749 100644 (file)
@@ -2047,6 +2047,48 @@ EXPRESSION: new DataView(new ArrayBuffer(16))
 }
 
 -----------------------------------------------------
+EXPRESSION: obj = {}; obj['prop'] = 1; obj[Symbol()] = 2; obj[Symbol('sym')] = 3; obj[Symbol('sym')] = 4; obj[Symbol.iterator] = Symbol(); obj
+{
+  "_type": "object",
+  "_objectId": "<filtered>",
+  "_description": "Object",
+  "_preview": {
+    "_type": "object",
+    "_description": "Object",
+    "_lossless": true,
+    "_overflow": false,
+    "_properties": [
+      {
+        "_name": "prop",
+        "_type": "number",
+        "_value": "1"
+      },
+      {
+        "_name": "Symbol()",
+        "_type": "number",
+        "_value": "2"
+      },
+      {
+        "_name": "Symbol(sym)",
+        "_type": "number",
+        "_value": "3"
+      },
+      {
+        "_name": "Symbol(sym)",
+        "_type": "number",
+        "_value": "4"
+      },
+      {
+        "_name": "Symbol(Symbol.iterator)",
+        "_type": "symbol",
+        "_value": "Symbol()"
+      }
+    ],
+    "_entries": null
+  }
+}
+
+-----------------------------------------------------
 EXPRESSION: document.body
 {
   "_type": "object",
index 7a8a69f..bc5f590 100644 (file)
@@ -265,5 +265,49 @@ ALL PROPERTIES:
     boundThis
     boundArgs
 -----------------------------------------------------
+
+-----------------------------------------------------
+EXPRESSION: window.objectWithSymbolProperties
+type: object
+description: Object
+
+OWN PROPERTIES:
+    prop
+    prop2
+    Symbol()
+    Symbol(sym)
+    Symbol(sym)
+    Symbol()
+    __proto__
+
+DISPLAYABLE PROPERTIES:
+    prop
+    prop2
+    Symbol()
+    Symbol(sym)
+    Symbol(sym)
+    Symbol()
+    __proto__
+
+ALL PROPERTIES:
+    prop
+    prop2
+    Symbol()
+    Symbol(sym)
+    Symbol(sym)
+    Symbol()
+    toString
+    toLocaleString
+    valueOf
+    hasOwnProperty
+    propertyIsEnumerable
+    isPrototypeOf
+    __defineGetter__
+    __defineSetter__
+    __lookupGetter__
+    __lookupSetter__
+    constructor
+    __proto__
+-----------------------------------------------------
 DONE
 
index ec785ad..a4546dc 100644 (file)
@@ -43,6 +43,7 @@ var complexObject = new SuperFoo;
 var badGetterObject = new ClassWithBadGetter;
 var unboundFunction = function() { console.log(arguments); }
 var boundFunction = unboundFunction.bind(document.body, 1, 2, 3);
+var objectWithSymbolProperties = {prop:1, [Symbol()]:2, [Symbol('sym')]:3, [Symbol('sym')]:4, [Symbol()]: Symbol(), prop2: 5};
 
 
 // --------
@@ -59,6 +60,7 @@ function test()
         {expression: "window.badGetterObject"},
         {expression: "window.unboundFunction"},
         {expression: "window.boundFunction"},
+        {expression: "window.objectWithSymbolProperties"},
     ]
 
     function runNextStep() {
index 4bd8f8f..384c5ae 100644 (file)
@@ -103,6 +103,7 @@ function test()
         {expression: "window.loadEvent"}, // window.loadEvent is set inside of <body onload="..."> below.
         {expression: "new ArrayBuffer(16)"},
         {expression: "new DataView(new ArrayBuffer(16))"},
+        {expression: "obj = {}; obj['prop'] = 1; obj[Symbol()] = 2; obj[Symbol('sym')] = 3; obj[Symbol('sym')] = 4; obj[Symbol.iterator] = Symbol(); obj"}, // Symbol properties
 
         // Node
         {expression: "document.body"},
index 69e6a14..69e5571 100644 (file)
@@ -1,3 +1,17 @@
+2015-04-07  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: ES6: Show Symbol properties on Objects
+        https://bugs.webkit.org/show_bug.cgi?id=141279
+
+        Reviewed by Timothy Hatcher.
+
+        * inspector/protocol/Runtime.json:
+        Give PropertyDescriptor a reference to the Symbol RemoteObject
+        if the property is a symbol property.
+
+        * inspector/InjectedScriptSource.js:
+        Enumerate symbol properties on objects.
+
 2015-04-07  Filip Pizlo  <fpizlo@apple.com>
 
         Make it possible to enable LLVM FastISel
index 8425c7b..d2c0c75 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007, 2014 Apple Inc.  All rights reserved.
+ * Copyright (C) 2007, 2014-2015 Apple Inc.  All rights reserved.
  * Copyright (C) 2013 Google Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -239,6 +239,8 @@ InjectedScript.prototype = {
                 descriptor.configurable = false;
             if (!("enumerable" in descriptor))
                 descriptor.enumerable = false;
+            if ("symbol" in descriptor)
+                descriptor.symbol = this._wrapObject(descriptor.symbol, objectGroupName);
         }
 
         return descriptors;
@@ -607,20 +609,25 @@ InjectedScript.prototype = {
     _propertyDescriptors: function(object, collectionMode)
     {
         var descriptors = [];
-        var nameProcessed = {};
-        nameProcessed["__proto__"] = null;
+        var nameProcessed = new Set;
 
-        function createFakeValueDescriptor(name, descriptor, isOwnProperty, possibleNativeBindingGetter)
+        function createFakeValueDescriptor(name, symbol, descriptor, isOwnProperty, possibleNativeBindingGetter)
         {
             try {
                 var descriptor = {name, value: object[name], writable: descriptor.writable || false, configurable: descriptor.configurable || false, enumerable: descriptor.enumerable || false};
                 if (possibleNativeBindingGetter)
                     descriptor.nativeGetter = true;
+                if (isOwnProperty)
+                    descriptor.isOwn = true;
+                if (symbol)
+                    descriptor.symbol = symbol;
                 return descriptor;
             } catch (e) {
                 var errorDescriptor = {name, value: e, wasThrown: true};
                 if (isOwnProperty)
                     errorDescriptor.isOwn = true;
+                if (symbol)
+                    errorDescriptor.symbol = symbol;
                 return errorDescriptor;
             }
         }
@@ -652,20 +659,23 @@ InjectedScript.prototype = {
             }
         }
 
-        function processPropertyNames(o, names, isOwnProperty)
+        function processProperties(o, properties, isOwnProperty)
         {
-            for (var i = 0; i < names.length; ++i) {
-                var name = names[i];
-                if (nameProcessed[name] || name === "__proto__")
+            for (var i = 0; i < properties.length; ++i) {
+                var property = properties[i];
+                if (nameProcessed.has(property) || property === "__proto__")
                     continue;
 
-                nameProcessed[name] = true;
+                nameProcessed.add(property);
+
+                var name = toString(property);
+                var symbol = isSymbol(property) ? property : null;
 
-                var descriptor = Object.getOwnPropertyDescriptor(o, name);
+                var descriptor = Object.getOwnPropertyDescriptor(o, property);
                 if (!descriptor) {
                     // FIXME: Bad descriptor. Can we get here?
                     // Fall back to very restrictive settings.
-                    var fakeDescriptor = createFakeValueDescriptor(name, {writable: false, configurable: false, enumerable: false}, isOwnProperty);
+                    var fakeDescriptor = createFakeValueDescriptor(name, symbol, {writable: false, configurable: false, enumerable: false}, isOwnProperty);
                     processDescriptor(fakeDescriptor, isOwnProperty);
                     continue;
                 }
@@ -674,7 +684,7 @@ InjectedScript.prototype = {
                     // FIXME: <https://webkit.org/b/140575> Web Inspector: Native Bindings Descriptors are Incomplete
                     // Developers may create such a descriptors, so we should be resilient:
                     // var x = {}; Object.defineProperty(x, "p", {get:undefined}); Object.getOwnPropertyDescriptor(x, "p")
-                    var fakeDescriptor = createFakeValueDescriptor(name, descriptor, isOwnProperty, true);
+                    var fakeDescriptor = createFakeValueDescriptor(name, symbol, descriptor, isOwnProperty, true);
                     processDescriptor(fakeDescriptor, isOwnProperty, true);
                     continue;
                 }
@@ -682,6 +692,8 @@ InjectedScript.prototype = {
                 descriptor.name = name;
                 if (isOwnProperty)
                     descriptor.isOwn = true;
+                if (symbol)
+                    descriptor.symbol = symbol;
                 processDescriptor(descriptor, isOwnProperty);
             }
         }
@@ -689,7 +701,9 @@ InjectedScript.prototype = {
         // Iterate prototype chain.
         for (var o = object; this._isDefined(o); o = o.__proto__) {
             var isOwnProperty = o === object;
-            processPropertyNames(o, Object.getOwnPropertyNames(o), isOwnProperty);
+            processProperties(o, Object.getOwnPropertyNames(o), isOwnProperty);
+            if (Object.getOwnPropertySymbols)
+                processProperties(o, Object.getOwnPropertySymbols(o), isOwnProperty);
             if (collectionMode === InjectedScript.CollectionMode.OwnProperties)
                 break;
         }
index a7dfb7e..73b6528 100644 (file)
@@ -71,7 +71,7 @@
             "type": "object",
             "description": "Object property descriptor.",
             "properties": [
-                { "name": "name", "type": "string", "description": "Property name." },
+                { "name": "name", "type": "string", "description": "Property name or symbol description." },
                 { "name": "value", "$ref": "RemoteObject", "optional": true, "description": "The value associated with the property." },
                 { "name": "writable", "type": "boolean", "optional": true, "description": "True if the value associated with the property may be changed (data descriptors only)." },
                 { "name": "get", "$ref": "RemoteObject", "optional": true, "description": "A function which serves as a getter for the property, or <code>undefined</code> if there is no getter (accessor descriptors only)." },
@@ -80,6 +80,7 @@
                 { "name": "enumerable", "type": "boolean", "description": "True if this property shows up during enumeration of the properties on the corresponding object." },
                 { "name": "wasThrown", "type": "boolean", "optional": true, "description": "True if the result was thrown during the evaluation." },
                 { "name": "isOwn", "optional": true, "type": "boolean", "description": "True if the property is owned for the object." },
+                { "name": "symbol", "optional": true, "$ref": "Runtime.RemoteObject", "description": "Property symbol object, if the property is a symbol." },
                 { "name": "nativeGetter", "optional": true, "type": "boolean", "description": "True if the property value came from a native getter." }
             ]
         },
index 72c1ae4..f1ac56d 100644 (file)
@@ -1,3 +1,31 @@
+2015-04-07  Joseph Pecoraro  <pecoraro@apple.com>
+
+        Web Inspector: ES6: Show Symbol properties on Objects
+        https://bugs.webkit.org/show_bug.cgi?id=141279
+
+        Reviewed by Timothy Hatcher.
+
+        * Localizations/en.lproj/localizedStrings.js:
+        * UserInterface/Models/PropertyDescriptor.js:
+        (WebInspector.PropertyDescriptor.get symbol):
+
+        * UserInterface/Protocol/RemoteObject.js:
+        (WebInspector.RemoteObject.wrappedCallback):
+        Update new PropertyDescriptor call site.
+
+        * UserInterface/Views/ObjectTreeBaseTreeElement.js:
+        (WebInspector.ObjectTreeBaseTreeElement._logSymbolProperty):
+        Provide a context menu for rows with Symbol properties to log
+        the Symbol property, and therefore get a reference to it.
+
+        * UserInterface/Views/ObjectTreeView.js:
+        (WebInspector.ObjectTreeView.comparePropertyDescriptors):
+        Better handle symbol properties in sorting.
+
+        * UserInterface/Views/TypePropertiesSection.js:
+        (WebInspector.TypePropertiesSection.PropertyComparator):
+        Return better value when values are equal.
+
 2015-04-07  Timothy Hatcher  <timothy@apple.com>
 
         Web Inspector: HierarchicalPathNavigationItem's additionalClassNames should be _additionalClassNames
index 9f2e20b..803a7f7 100644 (file)
Binary files a/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js and b/Source/WebInspectorUI/Localizations/en.lproj/localizedStrings.js differ
index dffd59d..cb69ce8 100644 (file)
@@ -25,7 +25,7 @@
 
 WebInspector.PropertyDescriptor = class PropertyDescriptor extends WebInspector.Object
 {
-    constructor(descriptor, isOwnProperty, wasThrown, nativeGetter, isInternalProperty)
+    constructor(descriptor, symbol, isOwnProperty, wasThrown, nativeGetter, isInternalProperty)
     {
         super();
 
@@ -34,12 +34,14 @@ WebInspector.PropertyDescriptor = class PropertyDescriptor extends WebInspector.
         console.assert(!descriptor.value || descriptor.value instanceof WebInspector.RemoteObject);
         console.assert(!descriptor.get || descriptor.get instanceof WebInspector.RemoteObject);
         console.assert(!descriptor.set || descriptor.set instanceof WebInspector.RemoteObject);
+        console.assert(!symbol || symbol instanceof WebInspector.RemoteObject);
 
         this._name = descriptor.name;
         this._value = descriptor.value;
         this._hasValue = "value" in descriptor;
         this._get = descriptor.get;
         this._set = descriptor.set;
+        this._symbol = symbol;
 
         this._writable = descriptor.writable || false;
         this._configurable = descriptor.configurable || false;
@@ -63,13 +65,16 @@ WebInspector.PropertyDescriptor = class PropertyDescriptor extends WebInspector.
         if (payload.set)
             payload.set = WebInspector.RemoteObject.fromPayload(payload.set);
 
+        if (payload.symbol)
+            payload.symbol = WebInspector.RemoteObject.fromPayload(payload.symbol);
+
         if (internal) {
             console.assert(payload.value);
             payload.writable = payload.configurable = payload.enumerable = false;
             payload.isOwn = true;
         }
 
-        return new WebInspector.PropertyDescriptor(payload, payload.isOwn, payload.wasThrown, payload.nativeGetter, internal);
+        return new WebInspector.PropertyDescriptor(payload, payload.symbol, payload.isOwn, payload.wasThrown, payload.nativeGetter, internal);
     }
 
     // Public
@@ -109,6 +114,11 @@ WebInspector.PropertyDescriptor = class PropertyDescriptor extends WebInspector.
         return this._enumerable;
     }
 
+    get symbol()
+    {
+        return this._symbol;
+    }
+
     get isOwnProperty()
     {
         return this._own;
@@ -148,4 +158,9 @@ WebInspector.PropertyDescriptor = class PropertyDescriptor extends WebInspector.
     {
         return !isNaN(Number(this._name));
     }
+
+    isSymbolProperty()
+    {
+        return !!this._symbol;
+    }
 };
index 1dd6e23..ee30632 100644 (file)
@@ -436,7 +436,7 @@ WebInspector.RemoteObject = class RemoteObject
             }
 
             var fakeDescriptor = {name: propertyName, value: result, writable: true, configurable: true, enumerable: false};
-            var fakePropertyDescriptor = new WebInspector.PropertyDescriptor(fakeDescriptor, true, false, false, false);
+            var fakePropertyDescriptor = new WebInspector.PropertyDescriptor(fakeDescriptor, null, true, false, false, false);
             callback(fakePropertyDescriptor);
         }
 
index c2f6d4d..7d11825 100644 (file)
@@ -154,6 +154,16 @@ WebInspector.ObjectTreeBaseTreeElement = class ObjectTreeBaseTreeElement extends
 
     // Private
 
+    _logSymbolProperty()
+    {
+        var symbol = this._property.symbol;
+        if (!symbol)
+            return;
+
+        var text = WebInspector.UIString("Selected Symbol");
+        WebInspector.consoleLogViewController.appendImmediateExecutionWithResult(text, symbol);
+    }
+
     _logValue(value)
     {
         var resolvedValue = value || this.resolvedValue();
@@ -177,6 +187,10 @@ WebInspector.ObjectTreeBaseTreeElement = class ObjectTreeBaseTreeElement extends
             return;
 
         var contextMenu = new WebInspector.ContextMenu(event);
+
+        if (this._property && this._property.symbol)
+            contextMenu.appendItem(WebInspector.UIString("Log Symbol"), this._logSymbolProperty.bind(this));
+
         contextMenu.appendItem(WebInspector.UIString("Log Value"), this._logValue.bind(this));
 
         var propertyPath = this.resolvedValuePropertyPath();
index 020906d..cda2bd4 100644 (file)
@@ -104,15 +104,21 @@ WebInspector.ObjectTreeView = class ObjectTreeView extends WebInspector.Object
         if (b === "__proto__")
             return -1;
 
-        // Put internal properties at the top.
-        if (a.isInternalProperty && !b.isInternalProperty)
+        // Put Internal properties at the top.
+        if (propertyA.isInternalProperty && !propertyB.isInternalProperty)
             return -1;
-        if (b.isInternalProperty && !a.isInternalProperty)
+        if (propertyB.isInternalProperty && !propertyA.isInternalProperty)
             return 1;
 
-        // if used elsewhere make sure to
-        //  - convert a and b to strings (not needed here, properties are all strings)
-        //  - check if a == b (not needed here, no two properties can be the same)
+        // Put Symbol properties at the bottom.
+        if (propertyA.symbol && !propertyB.symbol)
+            return 1;
+        if (propertyB.symbol && !propertyA.symbol)
+            return -1;
+
+        // Symbol properties may have the same description string but be different objects.
+        if (a === b)
+            return 0;
 
         var diff = 0;
         var chunk = /^\d+|^\D+/;
index 9e28d52..02af481 100644 (file)
@@ -90,7 +90,7 @@ WebInspector.TypePropertiesSection.PropertyComparator = function(propertyA, prop
     if (b.indexOf("__proto__") !== -1)
         return -1;
     if (a === b)
-        return 1;
+        return 0;
 
     var diff = 0;
     var chunk = /^\d+|^\D+/;