runtime icon indicating copy to clipboard operation
runtime copied to clipboard

[wasm][debugger] Object members that are protected accessors are not displayed in debugger window even though proxy is informed about them

Open thaystg opened this issue 3 years ago • 5 comments

Code:

    private void IncrementCount()
    {
        JObject myObj = new JObject();
        myObj.Add("thays", new JObject());
    }

Disable JustMyCode in Debugger settings.

Try to look at myObj in locals, you will not see the property ChildrenTokens, and we are able to see it in a .net6 app.

This is the definition of it: protected override IList<JToken> ChildrenTokens => _properties;

thaystg avatar Sep 16 '22 20:09 thaystg

Tagging subscribers to this area: @thaystg See info in area-owners.md if you want to be subscribed.

Issue Details

Code:

    private void IncrementCount()
    {
        JObject myObj = new JObject();
        myObj.Add("thays", new JObject());
    }

Disable JustMyCode in Debugger settings.

Try to look at myObj in locals, you will not see the property ChildrenTokens, and we are able to see it in a .net6 app.

This is the definition of it: protected override IList<JToken> ChildrenTokens => _properties;

Author: thaystg
Assignees: ilonatommy
Labels:

area-Debugger-mono

Milestone: 7.0.0

ghost avatar Sep 16 '22 20:09 ghost

Tagging subscribers to 'arch-wasm': @lewing See info in area-owners.md if you want to be subscribed.

Issue Details

Code:

    private void IncrementCount()
    {
        JObject myObj = new JObject();
        myObj.Add("thays", new JObject());
    }

Disable JustMyCode in Debugger settings.

Try to look at myObj in locals, you will not see the property ChildrenTokens, and we are able to see it in a .net6 app.

This is the definition of it: protected override IList<JToken> ChildrenTokens => _properties;

Author: thaystg
Assignees: ilonatommy
Labels:

arch-wasm, area-Debugger-mono

Milestone: 7.0.0

ghost avatar Sep 19 '22 16:09 ghost

Current behavior - no internal members: image

while in the reply we are including them:

{[Result: IsOk: True, IsErr: False, Value: {
  "result": [
    {
      "get": {
        "type": "function",
        "objectId": "dotnet:method:{\"isStatic\":false,\"containerId\":2,\"isValueType\":false,\"methodId\":24}",
        "className": "Function",
        "description": "get Type ()"
      },
      "name": "Type",
      "isOwn": true,
      "__section": "result",
      "__state": null,
      "__parentTypeId": 44,
      "__isNewSlot": false
    },
... etc ...
    {
      "get": {
        "type": "function",
        "objectId": "dotnet:method:{\"isStatic\":false,\"containerId\":2,\"isValueType\":false,\"methodId\":65}",
        "className": "Function",
        "description": "get Path ()"
      },
      "name": "Path",
      "isOwn": false,
      "__section": "result",
      "__state": null,
      "__parentTypeId": 6,
      "__isNewSlot": false
    }
  ],
  "privateProperties": [
    {
      "get": {
        "type": "function",
        "objectId": "dotnet:method:{\"isStatic\":false,\"containerId\":2,\"isValueType\":false,\"methodId\":29}",
        "className": "Function",
        "description": "get System.Collections.Generic.IDictionary<System.String,Newtonsoft.Json.Linq.JToken>.Keys ()"
      },
      "name": "System.Collections.Generic.IDictionary<System.String,Newtonsoft.Json.Linq.JToken>.Keys",
      "isOwn": true,
      "__section": "private",
      "__state": null,
      "__parentTypeId": 44,
      "__isNewSlot": true
    },
    ... etc ...
    {
      "get": {
        "type": "function",
        "objectId": "dotnet:method:{\"isStatic\":false,\"containerId\":2,\"isValueType\":false,\"methodId\":72}",
        "className": "Function",
        "description": "get Newtonsoft.Json.IJsonLineInfo.LinePosition ()"
      },
      "name": "Newtonsoft.Json.IJsonLineInfo.LinePosition",
      "isOwn": false,
      "__section": "private",
      "__state": null,
      "__parentTypeId": 6,
      "__isNewSlot": true
    }
  ],
  "internalProperties": [
    {
      "get": {
        "type": "function",
        "objectId": "dotnet:method:{\"isStatic\":false,\"containerId\":2,\"isValueType\":false,\"methodId\":23}",
        "className": "Function",
        "description": "get ChildrenTokens ()"
      },
      "name": "ChildrenTokens",
      "isOwn": true,
      "__section": "internal",
      "__state": null,
      "__parentTypeId": 44,
      "__isNewSlot": false
    }
  ]
}, Error:  ]}

When we switch off property level sorting the item is returned fine. For a normal, user-code non-overridden protected members the problem does not exist. For a user-code overridden protected members the problem is there as well, so it's not connected with JMC.

ilonatommy avatar Sep 20 '22 11:09 ilonatommy

Mininal repro:

    public class MyObject
    {
        public int publicVar => 0;
        internal int internalVar => 1;
        protected int protectedVar => 2;
        private int privateVar => 3;
    }
    
    private void IncrementCount()
    {
        var testMe = new MyObject(); // NOT OK
    }

image

We can't have tests for it because the Debugger Proxy response is correct and contains all 4 members.

Proxy's response is fine:

{[Result: IsOk: True, IsErr: False, Value: {
  "result": [
    {
      "get": {
        "type": "function",
        "objectId": "dotnet:method:{\"isStatic\":false,\"containerId\":2,\"isValueType\":false,\"methodId\":19}",
        "className": "Function",
        "description": "get publicVar ()"
      },
      "name": "publicVar",
      "isOwn": true,
      "__section": "result",
      "__state": null,
      "__parentTypeId": 7,
      "__isNewSlot": false
    }
  ],
  "privateProperties": [
    {
      "get": {
        "type": "function",
        "objectId": "dotnet:method:{\"isStatic\":false,\"containerId\":2,\"isValueType\":false,\"methodId\":22}",
        "className": "Function",
        "description": "get privateVar ()"
      },
      "name": "privateVar",
      "isOwn": true,
      "__section": "private",
      "__state": null,
      "__parentTypeId": 7,
      "__isNewSlot": false
    }
  ],
  "internalProperties": [
    {
      "get": {
        "type": "function",
        "objectId": "dotnet:method:{\"isStatic\":false,\"containerId\":2,\"isValueType\":false,\"methodId\":20}",
        "className": "Function",
        "description": "get internalVar ()"
      },
      "name": "internalVar",
      "isOwn": true,
      "__section": "internal",
      "__state": null,
      "__parentTypeId": 7,
      "__isNewSlot": false
    },
    {
      "get": {
        "type": "function",
        "objectId": "dotnet:method:{\"isStatic\":false,\"containerId\":2,\"isValueType\":false,\"methodId\":21}",
        "className": "Function",
        "description": "get protectedVar ()"
      },
      "name": "protectedVar",
      "isOwn": true,
      "__section": "internal",
      "__state": null,
      "__parentTypeId": 7,
      "__isNewSlot": false
    }
  ]
}, Error:  ]}

ilonatommy avatar Sep 20 '22 13:09 ilonatommy

The reason: while grouping the members by protection level we were populating internalProperties part of response with internal/protected members. In fact, internalProperties does not correspond with C#'s protection level internal and describes only properties in the js code that are not acessible to the programmer. When debugging a simple js class: image we can see that protected member is returned along with public member - in results: image. In this issue we should remove populating internalProperties and move its contents to result.

ilonatommy avatar Sep 20 '22 15:09 ilonatommy