* Merge main with @radical's refactoring.
* Fixed most tests.
* Added more Browsable tests: null + valuetype.
* Fixed trailing spaces and exposed the test.
* Fixed all GetPropertiesTests.
* Fixing RunOnCFOValueTypeResult.
* Fixed cloning to be deep.
* Reverted comments in test.
* Fixed browsable root hidden tests.
* Extended Browsable tests with a structure.
* Fixed TestSetValueOnObject.
* Add class testcase to browsable root hidden.
* All existing tests are passing.
* Cleanup, removing unused code.
* Added Browsable tests for nonstatic structures.
* Removed unnecessary comment.
* Removed whitespaces.
* Blocked tests failing/timeouting on Firefox.
internal bool IsEnCMethod;
internal LocalScopeHandleCollection localScopes;
public bool IsStatic() => (methodDef.Attributes & MethodAttributes.Static) != 0;
+ public MethodAttributes Attributes => methodDef.Attributes;
public int IsAsync { get; set; }
public DebuggerAttributesInfo DebuggerAttrInfo { get; set; }
public TypeInfo TypeInfo { get; }
internal sealed class DotnetObjectId
{
+ private int? _intValue;
+
public string Scheme { get; }
- public int Value { get; }
+ public int Value
+ {
+ get
+ {
+ if (_intValue == null)
+ throw new ArgumentException($"DotnetObjectId (scheme: {Scheme}, ValueAsJson: {ValueAsJson}) does not have an int value");
+ return _intValue.Value;
+ }
+ }
public int SubValue { get; set; }
- public bool IsValueType { get; set; }
+ public bool IsValueType => Scheme == "valuetype";
+
+ public JObject ValueAsJson { get; init; }
public static bool TryParse(JToken jToken, out DotnetObjectId objectId) => TryParse(jToken?.Value<string>(), out objectId);
public static bool TryParse(string id, out DotnetObjectId objectId)
{
objectId = null;
- try
- {
- if (id == null)
- return false;
-
- if (!id.StartsWith("dotnet:"))
- return false;
+ if (id == null)
+ return false;
- string[] parts = id.Split(":");
+ if (!id.StartsWith("dotnet:"))
+ return false;
- if (parts.Length < 3)
- return false;
+ string[] parts = id.Split(":", 3);
- objectId = new DotnetObjectId(parts[1], int.Parse(parts[2]));
- switch (objectId.Scheme)
- {
- case "methodId":
- if (parts.Length > 4)
- {
- objectId.SubValue = int.Parse(parts[3]);
- objectId.IsValueType = parts[4] == "ValueType";
- return true;
- }
- return false;
- }
- return true;
- }
- catch (Exception)
- {
+ if (parts.Length < 3)
return false;
- }
+
+ objectId = new DotnetObjectId(parts[1], parts[2]);
+ return true;
}
public DotnetObjectId(string scheme, int value)
- {
- Scheme = scheme;
- Value = value;
- }
+ : this(scheme, value.ToString()) { }
- public override string ToString()
+ public DotnetObjectId(string scheme, string value)
{
- switch (Scheme)
+ Scheme = scheme;
+ if (int.TryParse(value, out int ival))
{
- case "methodId":
- return $"dotnet:{Scheme}:{Value}:{SubValue}";
+ _intValue = ival;
+ }
+ else
+ {
+ try
+ {
+ ValueAsJson = JObject.Parse(value);
+ }
+ catch (JsonReaderException) { }
}
- return $"dotnet:{Scheme}:{Value}";
}
+
+ public override string ToString()
+ => _intValue != null
+ ? $"dotnet:{Scheme}:{_intValue}"
+ : $"dotnet:{Scheme}:{ValueAsJson}";
}
public struct Result
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
+using BrowserDebugProxy;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
var to = args?["to"].Value<string>().Replace("propertyIterator", "");
if (!DotnetObjectId.TryParse(to, out DotnetObjectId objectId))
return false;
- var res = await RuntimeGetPropertiesInternal(sessionId, objectId, args, token);
+ var res = await RuntimeGetObjectMembers(sessionId, objectId, args, token);
var variables = ConvertToFirefoxContent(res);
var o = JObject.FromObject(new
{
//{"iterator":{"type":"propertyIterator","actor":"server1.conn19.child63/propertyIterator73","count":3},"from":"server1.conn19.child63/obj71"}
if (!DotnetObjectId.TryParse(args?["to"], out DotnetObjectId objectId))
return false;
- var res = await RuntimeGetPropertiesInternal(sessionId, objectId, args, token);
+ var res = await RuntimeGetObjectMembers(sessionId, objectId, args, token);
var variables = ConvertToFirefoxContent(res);
var o = JObject.FromObject(new
{
if (ctx.CallStack == null)
return false;
Frame scope = ctx.CallStack.FirstOrDefault(s => s.Id == objectId.Value);
- var res = await RuntimeGetPropertiesInternal(sessionId, objectId, args, token);
+ var res = await RuntimeGetObjectMembers(sessionId, objectId, args, token);
var variables = ConvertToFirefoxContent(res);
var o = JObject.FromObject(new
{
return o;
}
- private static JObject ConvertToFirefoxContent(ValueOrError<JToken> res)
+ private static JObject ConvertToFirefoxContent(ValueOrError<GetMembersResult> res)
{
JObject variables = new JObject();
//TODO check if res.Error and do something
- foreach (var variable in res.Value)
+ var resVars = res.Value.Flatten();
+ foreach (var variable in resVars)
{
JObject variableDesc;
if (variable["get"] != null)
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.WebAssembly.Diagnostics;
+using Newtonsoft.Json.Linq;
+
+namespace BrowserDebugProxy
+{
+ internal static class MemberObjectsExplorer
+ {
+ private static bool IsACollectionType(string typeName)
+ => typeName is not null &&
+ (typeName.StartsWith("System.Collections.Generic", StringComparison.Ordinal) ||
+ typeName.EndsWith("[]", StringComparison.Ordinal));
+
+ private static string GetNamePrefixForValues(string memberName, string typeName, bool isOwn, DebuggerBrowsableState? state)
+ {
+ if (isOwn || state != DebuggerBrowsableState.RootHidden)
+ return memberName;
+
+ string justClassName = Path.GetExtension(typeName);
+ if (justClassName[0] == '.')
+ justClassName = justClassName[1..];
+ return $"{memberName} ({justClassName})";
+ }
+
+ private static async Task<JObject> ReadFieldValue(MonoSDBHelper sdbHelper, MonoBinaryReader reader, FieldTypeClass field, int objectId, TypeInfoWithDebugInformation typeInfo, int fieldValueType, bool isOwn, GetObjectCommandOptions getObjectOptions, CancellationToken token)
+ {
+ var fieldValue = await sdbHelper.CreateJObjectForVariableValue(
+ reader,
+ field.Name,
+ token,
+ isOwn: isOwn,
+ field.TypeId,
+ getObjectOptions.HasFlag(GetObjectCommandOptions.ForDebuggerDisplayAttribute));
+
+ var typeFieldsBrowsableInfo = typeInfo?.Info?.DebuggerBrowsableFields;
+ var typePropertiesBrowsableInfo = typeInfo?.Info?.DebuggerBrowsableProperties;
+
+ if (!typeFieldsBrowsableInfo.TryGetValue(field.Name, out DebuggerBrowsableState? state))
+ {
+ // for backing fields, we are getting it from the properties
+ typePropertiesBrowsableInfo.TryGetValue(field.Name, out state);
+ }
+ fieldValue["__state"] = state?.ToString();
+
+ fieldValue["__section"] = field.Attributes switch
+ {
+ FieldAttributes.Private => "private",
+ FieldAttributes.Public => "result",
+ _ => "internal"
+ };
+ if (field.IsBackingField)
+ fieldValue["__isBackingField"] = true;
+ if (field.Attributes.HasFlag(FieldAttributes.Static))
+ fieldValue["__isStatic"] = true;
+
+ if (getObjectOptions.HasFlag(GetObjectCommandOptions.WithSetter))
+ {
+ var command_params_writer_to_set = new MonoBinaryWriter();
+ command_params_writer_to_set.Write(objectId);
+ command_params_writer_to_set.Write(1);
+ command_params_writer_to_set.Write(field.Id);
+ var (data, length) = command_params_writer_to_set.ToBase64();
+
+ fieldValue.Add("set", JObject.FromObject(new
+ {
+ commandSet = CommandSet.ObjectRef,
+ command = CmdObject.RefSetValues,
+ buffer = data,
+ valtype = fieldValueType,
+ length = length,
+ id = MonoSDBHelper.GetNewId()
+ }));
+ }
+
+ return fieldValue;
+ }
+
+ private static async Task<JArray> GetRootHiddenChildren(
+ MonoSDBHelper sdbHelper,
+ JObject root,
+ string rootNamePrefix,
+ string rootTypeName,
+ GetObjectCommandOptions getCommandOptions,
+ bool includeStatic,
+ CancellationToken token)
+ {
+ var rootValue = root?["value"] ?? root["get"];
+
+ if (rootValue?["subtype"]?.Value<string>() == "null")
+ return new JArray();
+
+ var type = rootValue?["type"]?.Value<string>();
+ if (type != "object" && type != "function")
+ return new JArray();
+
+ if (!DotnetObjectId.TryParse(rootValue?["objectId"]?.Value<string>(), out DotnetObjectId rootObjectId))
+ throw new Exception($"Cannot parse object id from {root} for {rootNamePrefix}");
+
+ // if it's an accessor
+ if (root["get"] != null)
+ return await GetRootHiddenChildrenForProperty();
+
+ if (rootValue?["type"]?.Value<string>() != "object")
+ return new JArray();
+
+ // unpack object/valuetype
+ if (rootObjectId.Scheme is "object" or "valuetype")
+ {
+ GetMembersResult members;
+ if (rootObjectId.Scheme is "valuetype")
+ {
+ var valType = sdbHelper.GetValueTypeClass(rootObjectId.Value);
+ if (valType == null || valType.IsEnum)
+ return new JArray();
+ members = await valType.GetMemberValues(sdbHelper, getCommandOptions, false, includeStatic, token);
+ }
+ else members = await GetObjectMemberValues(sdbHelper, rootObjectId.Value, getCommandOptions, token, false, includeStatic);
+
+ if (!IsACollectionType(rootTypeName))
+ {
+ // is a class/valuetype with members
+ var resultValue = members.Flatten();
+ foreach (var item in resultValue)
+ item["name"] = $"{rootNamePrefix}.{item["name"]}";
+ return resultValue;
+ }
+ else
+ {
+ // a collection - expose elements to be of array scheme
+ var memberNamedItems = members
+ .Where(m => m["name"]?.Value<string>() == "Items" || m["name"]?.Value<string>() == "_items")
+ .FirstOrDefault();
+ if (memberNamedItems is not null &&
+ (DotnetObjectId.TryParse(memberNamedItems["value"]?["objectId"]?.Value<string>(), out DotnetObjectId itemsObjectId)) &&
+ itemsObjectId.Scheme == "array")
+ {
+ rootObjectId = itemsObjectId;
+ }
+ }
+ }
+
+ if (rootObjectId.Scheme == "array")
+ {
+ JArray resultValue = await sdbHelper.GetArrayValues(rootObjectId.Value, token);
+
+ // root hidden item name has to be unique, so we concatenate the root's name to it
+ foreach (var item in resultValue)
+ item["name"] = $"{rootNamePrefix}[{item["name"]}]";
+
+ return resultValue;
+ }
+ else
+ {
+ return new JArray();
+ }
+
+ async Task<JArray> GetRootHiddenChildrenForProperty()
+ {
+ var resMethod = await sdbHelper.InvokeMethod(rootObjectId, token);
+ return await GetRootHiddenChildren(sdbHelper, resMethod, rootNamePrefix, rootTypeName, getCommandOptions, includeStatic, token);
+ }
+ }
+
+ public static Task<GetMembersResult> GetTypeMemberValues(
+ MonoSDBHelper sdbHelper,
+ DotnetObjectId dotnetObjectId,
+ GetObjectCommandOptions getObjectOptions,
+ CancellationToken token,
+ bool sortByAccessLevel = false,
+ bool includeStatic = false)
+ => dotnetObjectId.IsValueType
+ ? GetValueTypeMemberValues(sdbHelper, dotnetObjectId.Value, getObjectOptions, token, sortByAccessLevel, includeStatic)
+ : GetObjectMemberValues(sdbHelper, dotnetObjectId.Value, getObjectOptions, token, sortByAccessLevel, includeStatic);
+
+ public static async Task<JArray> ExpandFieldValues(
+ MonoSDBHelper sdbHelper,
+ DotnetObjectId id,
+ int containerTypeId,
+ IReadOnlyList<FieldTypeClass> fields,
+ GetObjectCommandOptions getCommandOptions,
+ bool isOwn,
+ bool includeStatic,
+ CancellationToken token)
+ {
+ JArray fieldValues = new JArray();
+ if (fields.Count == 0)
+ return fieldValues;
+
+ if (getCommandOptions.HasFlag(GetObjectCommandOptions.ForDebuggerProxyAttribute))
+ fields = fields.Where(field => field.IsNotPrivate).ToList();
+
+ using var commandParamsWriter = new MonoBinaryWriter();
+ commandParamsWriter.Write(id.Value);
+ commandParamsWriter.Write(fields.Count);
+ foreach (var field in fields)
+ commandParamsWriter.Write(field.Id);
+ MonoBinaryReader retDebuggerCmdReader = id.IsValueType
+ ? await sdbHelper.SendDebuggerAgentCommand(CmdType.GetValues, commandParamsWriter, token) :
+ await sdbHelper.SendDebuggerAgentCommand(CmdObject.RefGetValues, commandParamsWriter, token);
+
+ var typeInfo = await sdbHelper.GetTypeInfo(containerTypeId, token);
+
+ int numFieldsRead = 0;
+ foreach (FieldTypeClass field in fields)
+ {
+ long initialPos = retDebuggerCmdReader.BaseStream.Position;
+ int valtype = retDebuggerCmdReader.ReadByte();
+ retDebuggerCmdReader.BaseStream.Position = initialPos;
+
+ JObject fieldValue = await ReadFieldValue(sdbHelper, retDebuggerCmdReader, field, id.Value, typeInfo, valtype, isOwn, getCommandOptions, token);
+ numFieldsRead++;
+
+ if (!Enum.TryParse(fieldValue["__state"].Value<string>(), out DebuggerBrowsableState fieldState)
+ || fieldState == DebuggerBrowsableState.Collapsed)
+ {
+ fieldValues.Add(fieldValue);
+ continue;
+ }
+
+ if (fieldState == DebuggerBrowsableState.Never)
+ continue;
+
+ string namePrefix = field.Name;
+ string containerTypeName = await sdbHelper.GetTypeName(containerTypeId, token);
+ namePrefix = GetNamePrefixForValues(field.Name, containerTypeName, isOwn, fieldState);
+ string typeName = await sdbHelper.GetTypeName(field.TypeId, token);
+
+ var enumeratedValues = await GetRootHiddenChildren(
+ sdbHelper, fieldValue, namePrefix, typeName, getCommandOptions, includeStatic, token);
+ if (enumeratedValues != null)
+ fieldValues.AddRange(enumeratedValues);
+ }
+
+ if (numFieldsRead != fields.Count)
+ throw new Exception($"Bug: Got {numFieldsRead} instead of expected {fields.Count} field values");
+
+ return fieldValues;
+ }
+
+ public static Task<GetMembersResult> GetValueTypeMemberValues(
+ MonoSDBHelper sdbHelper, int valueTypeId, GetObjectCommandOptions getCommandOptions, CancellationToken token, bool sortByAccessLevel = false, bool includeStatic = false)
+ {
+ return sdbHelper.valueTypes.TryGetValue(valueTypeId, out ValueTypeClass valueType)
+ ? valueType.GetMemberValues(sdbHelper, getCommandOptions, sortByAccessLevel, includeStatic, token)
+ : throw new ArgumentException($"Could not find any valuetype with id: {valueTypeId}", nameof(valueTypeId));
+ }
+
+ public static async Task<JArray> GetExpandedMemberValues(
+ MonoSDBHelper sdbHelper,
+ string typeName,
+ string namePrefix,
+ JObject value,
+ DebuggerBrowsableState? state,
+ bool includeStatic,
+ CancellationToken token)
+ {
+ if (state is DebuggerBrowsableState.RootHidden)
+ {
+ if (MonoSDBHelper.IsPrimitiveType(typeName))
+ return GetHiddenElement();
+
+ return await GetRootHiddenChildren(sdbHelper, value, namePrefix, typeName, GetObjectCommandOptions.None, includeStatic, token);
+
+ }
+ else if (state is DebuggerBrowsableState.Never)
+ {
+ return GetHiddenElement();
+ }
+ return new JArray(value);
+
+ JArray GetHiddenElement()
+ {
+ return new JArray(JObject.FromObject(new
+ {
+ name = namePrefix,
+ __hidden = true
+ }));
+ }
+ }
+
+ public static async Task<Dictionary<string, JObject>> GetNonAutomaticPropertyValues(
+ MonoSDBHelper sdbHelper,
+ int typeId,
+ string containerTypeName,
+ ArraySegment<byte> getterParamsBuffer,
+ bool isAutoExpandable,
+ DotnetObjectId objectId,
+ bool isValueType,
+ bool isOwn,
+ CancellationToken token,
+ Dictionary<string, JObject> allMembers,
+ bool includeStatic = false)
+ {
+ using var retDebuggerCmdReader = await sdbHelper.GetTypePropertiesReader(typeId, token);
+ if (retDebuggerCmdReader == null)
+ return null;
+
+ var nProperties = retDebuggerCmdReader.ReadInt32();
+ var typeInfo = await sdbHelper.GetTypeInfo(typeId, token);
+ var typePropertiesBrowsableInfo = typeInfo?.Info?.DebuggerBrowsableProperties;
+
+ GetMembersResult ret = new();
+ for (int i = 0; i < nProperties; i++)
+ {
+ retDebuggerCmdReader.ReadInt32(); //propertyId
+ string propName = retDebuggerCmdReader.ReadString();
+ var getMethodId = retDebuggerCmdReader.ReadInt32();
+ retDebuggerCmdReader.ReadInt32(); //setmethod
+ var attrs = (PropertyAttributes)retDebuggerCmdReader.ReadInt32(); //attrs
+ if (getMethodId == 0 || await sdbHelper.GetParamCount(getMethodId, token) != 0)
+ continue;
+ if (!includeStatic && await sdbHelper.MethodIsStatic(getMethodId, token))
+ continue;
+
+ MethodInfoWithDebugInformation getterInfo = await sdbHelper.GetMethodInfo(getMethodId, token);
+ MethodAttributes getterAttrs = getterInfo?.Info.Attributes ?? MethodAttributes.Public;
+ getterAttrs &= MethodAttributes.MemberAccessMask;
+
+ typePropertiesBrowsableInfo.TryGetValue(propName, out DebuggerBrowsableState? state);
+
+ if (allMembers.TryGetValue(propName, out JObject backingField))
+ {
+ if (backingField["__isBackingField"]?.Value<bool>() == true)
+ {
+ // Update backingField's access with the one from the property getter
+ backingField["__section"] = getterAttrs switch
+ {
+ MethodAttributes.Private => "private",
+ MethodAttributes.Public => "result",
+ _ => "internal"
+ };
+ backingField["__state"] = state?.ToString();
+
+ if (state is not null)
+ {
+ string namePrefix = GetNamePrefixForValues(propName, containerTypeName, isOwn, state);
+
+ string backingFieldTypeName = backingField["value"]?["className"]?.Value<string>();
+ var expanded = await GetExpandedMemberValues(
+ sdbHelper, backingFieldTypeName, namePrefix, backingField, state, includeStatic, token);
+ backingField.Remove();
+ allMembers.Remove(propName);
+ foreach (JObject evalue in expanded)
+ allMembers[evalue["name"].Value<string>()] = evalue;
+ }
+ }
+
+ // derived type already had a member of this name
+ continue;
+ }
+ else
+ {
+ string returnTypeName = await sdbHelper.GetReturnType(getMethodId, token);
+ JObject propRet = null;
+ if (isAutoExpandable || (state is DebuggerBrowsableState.RootHidden && IsACollectionType(returnTypeName)))
+ {
+ try
+ {
+ propRet = await sdbHelper.InvokeMethod(getterParamsBuffer, getMethodId, token, name: propName);
+ }
+ catch (Exception)
+ {
+ continue;
+ }
+ }
+ else
+ propRet = GetNotAutoExpandableObject(getMethodId, propName);
+
+ propRet["isOwn"] = isOwn;
+ propRet["__section"] = getterAttrs switch
+ {
+ MethodAttributes.Private => "private",
+ MethodAttributes.Public => "result",
+ _ => "internal"
+ };
+ propRet["__state"] = state?.ToString();
+
+ string namePrefix = GetNamePrefixForValues(propName, containerTypeName, isOwn, state);
+ var expandedMembers = await GetExpandedMemberValues(
+ sdbHelper, returnTypeName, namePrefix, propRet, state, includeStatic, token);
+ foreach (var member in expandedMembers)
+ {
+ var key = member["name"]?.Value<string>();
+ if (key != null)
+ {
+ allMembers.TryAdd(key, member as JObject);
+ }
+ }
+ }
+ }
+ return allMembers;
+
+ JObject GetNotAutoExpandableObject(int methodId, string propertyName)
+ {
+ JObject methodIdArgs = JObject.FromObject(new
+ {
+ containerId = objectId.Value,
+ isValueType = isValueType,
+ methodId = methodId
+ });
+
+ return JObject.FromObject(new
+ {
+ get = new
+ {
+ type = "function",
+ objectId = $"dotnet:method:{methodIdArgs.ToString(Newtonsoft.Json.Formatting.None)}",
+ className = "Function",
+ description = "get " + propertyName + " ()"
+ },
+ name = propertyName
+ });
+ }
+ }
+
+ public static async Task<GetMembersResult> GetObjectMemberValues(
+ MonoSDBHelper sdbHelper,
+ int objectId,
+ GetObjectCommandOptions getCommandType,
+ CancellationToken token,
+ bool sortByAccessLevel = false,
+ bool includeStatic = false)
+ {
+ if (await sdbHelper.IsDelegate(objectId, token))
+ {
+ var description = await sdbHelper.GetDelegateMethodDescription(objectId, token);
+ var objValues = JObject.FromObject(new
+ {
+ value = new
+ {
+ type = "symbol",
+ value = description,
+ description
+ },
+ name = "Target"
+ });
+
+ return GetMembersResult.FromValues(new List<JObject>() { objValues });
+ }
+
+ // 1
+ var typeIdsIncludingParents = await sdbHelper.GetTypeIdsForObject(objectId, true, token);
+
+ // 2
+ if (!getCommandType.HasFlag(GetObjectCommandOptions.ForDebuggerDisplayAttribute))
+ {
+ GetMembersResult debuggerProxy = await sdbHelper.GetValuesFromDebuggerProxyAttribute(objectId, typeIdsIncludingParents[0], token);
+ if (debuggerProxy != null)
+ return debuggerProxy;
+ }
+
+ // 3. GetProperties
+ DotnetObjectId id = new DotnetObjectId("object", objectId);
+ using var commandParamsObjWriter = new MonoBinaryWriter();
+ commandParamsObjWriter.WriteObj(id, sdbHelper);
+ ArraySegment<byte> getPropertiesParamBuffer = commandParamsObjWriter.GetParameterBuffer();
+
+ var allMembers = new Dictionary<string, JObject>();
+ for (int i = 0; i < typeIdsIncludingParents.Count; i++)
+ {
+ int typeId = typeIdsIncludingParents[i];
+ string typeName = await sdbHelper.GetTypeName(typeId, token);
+ // 0th id is for the object itself, and then its ancestors
+ bool isOwn = i == 0;
+ IReadOnlyList<FieldTypeClass> thisTypeFields = await sdbHelper.GetTypeFields(typeId, token);
+ if (!includeStatic)
+ thisTypeFields = thisTypeFields.Where(f => !f.Attributes.HasFlag(FieldAttributes.Static)).ToList();
+ if (thisTypeFields.Count > 0)
+ {
+ var allFields = await ExpandFieldValues(
+ sdbHelper, id, typeId, thisTypeFields, getCommandType, isOwn, includeStatic, token);
+
+ if (getCommandType.HasFlag(GetObjectCommandOptions.AccessorPropertiesOnly))
+ {
+ foreach (var f in allFields)
+ f["__hidden"] = true;
+ }
+ AddOnlyNewValuesByNameTo(allFields, allMembers, isOwn);
+ }
+
+ // skip loading properties if not necessary
+ if (!getCommandType.HasFlag(GetObjectCommandOptions.WithProperties))
+ return GetMembersResult.FromValues(allMembers.Values, sortByAccessLevel);
+
+ allMembers = await GetNonAutomaticPropertyValues(
+ sdbHelper,
+ typeId,
+ typeName,
+ getPropertiesParamBuffer,
+ getCommandType.HasFlag(GetObjectCommandOptions.ForDebuggerProxyAttribute),
+ id,
+ isValueType: false,
+ isOwn,
+ token,
+ allMembers);
+
+ // ownProperties
+ // Note: ownProperties should mean that we return members of the klass itself,
+ // but we are going to ignore that here, because otherwise vscode/chrome don't
+ // seem to ask for inherited fields at all.
+ //if (ownProperties)
+ //break;
+ /*if (accessorPropertiesOnly)
+ break;*/
+ }
+ return GetMembersResult.FromValues(allMembers.Values, sortByAccessLevel);
+
+ static void AddOnlyNewValuesByNameTo(JArray namedValues, IDictionary<string, JObject> valuesDict, bool isOwn)
+ {
+ foreach (var item in namedValues)
+ {
+ var key = item["name"]?.Value<string>();
+ if (key != null)
+ {
+ valuesDict.TryAdd(key, item as JObject);
+ }
+ }
+ }
+ }
+
+ }
+
+ internal sealed class GetMembersResult
+ {
+ // public:
+ public JArray Result { get; set; }
+ // private:
+ public JArray PrivateMembers { get; set; }
+ // protected / internal:
+ public JArray OtherMembers { get; set; }
+
+ public JObject JObject => JObject.FromObject(new
+ {
+ result = Result,
+ privateProperties = PrivateMembers,
+ internalProperties = OtherMembers
+ });
+
+ public GetMembersResult()
+ {
+ Result = new JArray();
+ PrivateMembers = new JArray();
+ OtherMembers = new JArray();
+ }
+
+ public GetMembersResult(JArray value, bool sortByAccessLevel)
+ {
+ var t = FromValues(value, sortByAccessLevel);
+ Result = t.Result;
+ PrivateMembers = t.PrivateMembers;
+ OtherMembers = t.OtherMembers;
+ }
+
+ public static GetMembersResult FromValues(IEnumerable<JToken> values, bool splitMembersByAccessLevel = false) =>
+ FromValues(new JArray(values), splitMembersByAccessLevel);
+
+ public static GetMembersResult FromValues(JArray values, bool splitMembersByAccessLevel = false)
+ {
+ GetMembersResult result = new();
+ if (splitMembersByAccessLevel)
+ {
+ foreach (var member in values)
+ result.Split(member);
+ return result;
+ }
+ result.Result.AddRange(values);
+ return result;
+ }
+
+ private void Split(JToken member)
+ {
+ if (member["__hidden"]?.Value<bool>() == true)
+ return;
+
+ if (member["__section"]?.Value<string>() is not string section)
+ {
+ Result.Add(member);
+ return;
+ }
+
+ switch (section)
+ {
+ case "private":
+ PrivateMembers.Add(member);
+ return;
+ case "internal":
+ OtherMembers.Add(member);
+ return;
+ default:
+ Result.Add(member);
+ return;
+ }
+ }
+
+ public GetMembersResult Clone() => new GetMembersResult()
+ {
+ Result = (JArray)Result.DeepClone(),
+ PrivateMembers = (JArray)PrivateMembers.DeepClone(),
+ OtherMembers = (JArray)OtherMembers.DeepClone()
+ };
+
+ public IEnumerable<JToken> Where(Func<JToken, bool> predicate)
+ {
+ foreach (var item in Result)
+ {
+ if (predicate(item))
+ {
+ yield return item;
+ }
+ }
+ foreach (var item in PrivateMembers)
+ {
+ if (predicate(item))
+ {
+ yield return item;
+ }
+ }
+ foreach (var item in OtherMembers)
+ {
+ if (predicate(item))
+ {
+ yield return item;
+ }
+ }
+ }
+
+ internal JToken FirstOrDefault(Func<JToken, bool> p)
+ => Result.FirstOrDefault(p)
+ ?? PrivateMembers.FirstOrDefault(p)
+ ?? OtherMembers.FirstOrDefault(p);
+
+ internal JArray Flatten()
+ {
+ var result = new JArray();
+ result.AddRange(Result);
+ result.AddRange(PrivateMembers);
+ result.AddRange(OtherMembers);
+ return result;
+ }
+ public override string ToString() => $"{JObject}\n";
+ }
+}
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Generic;
using System.Net.WebSockets;
+using BrowserDebugProxy;
namespace Microsoft.WebAssembly.Diagnostics
{
{
if (DotnetObjectId.TryParse(objRet?["value"]?["objectId"]?.Value<string>(), out DotnetObjectId objectId))
{
- var exceptionObject = await context.SdbAgent.GetObjectValues(objectId.Value, GetObjectCommandOptions.WithProperties | GetObjectCommandOptions.OwnProperties, token);
+ GetMembersResult exceptionObject = await MemberObjectsExplorer.GetTypeMemberValues(context.SdbAgent, objectId, GetObjectCommandOptions.WithProperties | GetObjectCommandOptions.OwnProperties, token);
var exceptionObjectMessage = exceptionObject.FirstOrDefault(attr => attr["name"].Value<string>().Equals("_message"));
exceptionObjectMessage["value"]["value"] = objRet["value"]?["className"]?.Value<string>() + ": " + exceptionObjectMessage["value"]?["value"]?.Value<string>();
return exceptionObjectMessage["value"]?.Value<JObject>();
if (objRet["value"]?.Value<JObject>() != null)
return objRet["value"]?.Value<JObject>();
- if (objRet["get"]?.Value<JObject>() != null)
- {
- if (DotnetObjectId.TryParse(objRet?["get"]?["objectIdValue"]?.Value<string>(), out DotnetObjectId objectId))
- {
- using var commandParamsWriter = new MonoBinaryWriter();
- commandParamsWriter.WriteObj(objectId, context.SdbAgent);
- var ret = await context.SdbAgent.InvokeMethod(commandParamsWriter.GetParameterBuffer(), objRet["get"]["methodId"].Value<int>(), objRet["name"].Value<string>(), token);
- return await GetValueFromObject(ret, token);
- }
+ if (objRet["get"]?.Value<JObject>() != null &&
+ DotnetObjectId.TryParse(objRet?["get"]?["objectId"]?.Value<string>(), out DotnetObjectId getterObjectId))
+ {
+ var ret = await context.SdbAgent.InvokeMethod(getterObjectId, token);
+ return await GetValueFromObject(ret, token);
}
return null;
}
{
using var commandParamsObjWriter = new MonoBinaryWriter();
commandParamsObjWriter.Write(0); //param count
- var retMethod = await context.SdbAgent.InvokeMethod(commandParamsObjWriter.GetParameterBuffer(), methodId, "methodRet", token);
+ var retMethod = await context.SdbAgent.InvokeMethod(commandParamsObjWriter.GetParameterBuffer(), methodId, token);
return await GetValueFromObject(retMethod, token);
}
return null;
if (!DotnetObjectId.TryParse(objThis?["value"]?["objectId"]?.Value<string>(), out DotnetObjectId objectId))
return null;
- ValueOrError<JToken> valueOrError = await proxy.RuntimeGetPropertiesInternal(sessionId, objectId, null, token);
+ ValueOrError<GetMembersResult> valueOrError = await proxy.RuntimeGetObjectMembers(sessionId, objectId, null, token);
if (valueOrError.IsError)
{
logger.LogDebug($"ResolveAsLocalOrThisMember failed with : {valueOrError.Error}");
if (!DotnetObjectId.TryParse(resolvedObject?["objectId"]?.Value<string>(), out DotnetObjectId objectId))
return null;
- ValueOrError<JToken> valueOrError = await proxy.RuntimeGetPropertiesInternal(sessionId, objectId, null, token);
+ ValueOrError<GetMembersResult> valueOrError = await proxy.RuntimeGetObjectMembers(sessionId, objectId, null, token);
if (valueOrError.IsError)
{
logger.LogDebug($"ResolveAsInstanceMember failed with : {valueOrError.Error}");
rootObject["value"] = await context.SdbAgent.GetArrayValues(objectId.Value, token);
return (JObject)rootObject["value"][elementIdx]["value"];
case "object":
- var typeIds = await context.SdbAgent.GetTypeIdFromObject(objectId.Value, true, token);
+ var typeIds = await context.SdbAgent.GetTypeIdsForObject(objectId.Value, true, token);
int methodId = await context.SdbAgent.GetMethodIdByName(typeIds[0], "ToArray", token);
- var toArrayRetMethod = await context.SdbAgent.InvokeMethodInObject(objectId, methodId, elementAccess.Expression.ToString(), token);
+ var toArrayRetMethod = await context.SdbAgent.InvokeMethod(objectId.Value, methodId, isValueType: false, token);
rootObject = await GetValueFromObject(toArrayRetMethod, token);
DotnetObjectId.TryParse(rootObject?["objectId"]?.Value<string>(), out DotnetObjectId arrayObjectId);
rootObject["value"] = await context.SdbAgent.GetArrayValues(arrayObjectId.Value, token);
if (!DotnetObjectId.TryParse(rootObject?["objectId"]?.Value<string>(), out DotnetObjectId objectId))
throw new ExpressionEvaluationFailedException($"Cannot invoke method '{methodName}' on invalid object id: {rootObject}");
- var typeIds = await context.SdbAgent.GetTypeIdFromObject(objectId.Value, true, token);
+ List<int> typeIds;
+ if (objectId.IsValueType)
+ {
+ if (!context.SdbAgent.valueTypes.TryGetValue(objectId.Value, out ValueTypeClass valueType))
+ throw new Exception($"Could not find valuetype {objectId}");
+
+ typeIds = new List<int>(1) { valueType.TypeId };
+ }
+ else
+ {
+ typeIds = await context.SdbAgent.GetTypeIdsForObject(objectId.Value, true, token);
+ }
int methodId = await context.SdbAgent.GetMethodIdByName(typeIds[0], methodName, token);
var className = await context.SdbAgent.GetTypeNameOriginal(typeIds[0], token);
if (methodId == 0) //try to search on System.Linq.Enumerable
if (!await commandParamsObjWriter.WriteConst(methodParamsInfo[argIndex].TypeCode, methodParamsInfo[argIndex].Value, context.SdbAgent, token))
throw new InternalErrorException($"Unable to write optional parameter {methodParamsInfo[argIndex].Name} value in method '{methodName}' to the mono buffer.");
}
- var retMethod = await context.SdbAgent.InvokeMethod(commandParamsObjWriter.GetParameterBuffer(), methodId, "methodRet", token);
+ var retMethod = await context.SdbAgent.InvokeMethod(commandParamsObjWriter.GetParameterBuffer(), methodId, token);
return await GetValueFromObject(retMethod, token);
}
}
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Net.Http;
+using BrowserDebugProxy;
namespace Microsoft.WebAssembly.Diagnostics
{
if (!DotnetObjectId.TryParse(args?["objectId"], out DotnetObjectId objectId))
break;
- var valueOrError = await RuntimeGetPropertiesInternal(id, objectId, args, token, true);
+ var valueOrError = await RuntimeGetObjectMembers(id, objectId, args, token, true);
if (valueOrError.IsError)
{
logger.LogDebug($"Runtime.getProperties: {valueOrError.Error}");
SendResponse(id, valueOrError.Error.Value, token);
+ return true;
}
- else
+ if (valueOrError.Value.JObject == null)
{
- SendResponse(id, Result.OkFromObject(valueOrError.Value), token);
+ SendResponse(id, Result.Err($"Failed to get properties for '{objectId}'"), token);
+ return true;
}
+ SendResponse(id, Result.OkFromObject(valueOrError.Value.JObject), token);
return true;
}
}
switch (objectId.Scheme)
{
+ case "method":
+ args["details"] = await context.SdbAgent.GetMethodProxy(objectId.ValueAsJson, token);
+ break;
case "object":
- case "methodId":
args["details"] = await context.SdbAgent.GetObjectProxy(objectId.Value, token);
break;
case "valuetype":
args["details"] = await context.SdbAgent.GetArrayValuesProxy(objectId.Value, token);
break;
case "cfo_res":
- {
Result cfo_res = await SendMonoCommand(id, MonoCommands.CallFunctionOn(RuntimeId, args), token);
cfo_res = Result.OkFromObject(new { result = cfo_res.Value?["result"]?["value"]});
SendResponse(id, cfo_res, token);
return true;
- }
case "scope":
{
SendResponse(id,
byte[] newBytes = Convert.FromBase64String(res.Value?["result"]?["value"]?["value"]?.Value<string>());
var retDebuggerCmdReader = new MonoBinaryReader(newBytes);
retDebuggerCmdReader.ReadByte(); //number of objects returned.
- var obj = await context.SdbAgent.CreateJObjectForVariableValue(retDebuggerCmdReader, "ret", false, -1, false, token);
+ var obj = await context.SdbAgent.CreateJObjectForVariableValue(retDebuggerCmdReader, "ret", token);
/*JTokenType? res_value_type = res.Value?["result"]?["value"]?.Type;*/
res = Result.OkFromObject(new { result = obj["value"]});
SendResponse(id, res, token);
return true;
}
- internal async Task<ValueOrError<JToken>> RuntimeGetPropertiesInternal(SessionId id, DotnetObjectId objectId, JToken args, CancellationToken token, bool sortByAccessLevel = false)
+ internal async Task<ValueOrError<GetMembersResult>> RuntimeGetObjectMembers(SessionId id, DotnetObjectId objectId, JToken args, CancellationToken token, bool sortByAccessLevel = false)
{
var context = GetContext(id);
- var accessorPropertiesOnly = false;
- GetObjectCommandOptions objectValuesOpt = GetObjectCommandOptions.WithProperties;
+ GetObjectCommandOptions getObjectOptions = GetObjectCommandOptions.WithProperties;
if (args != null)
{
if (args["accessorPropertiesOnly"] != null && args["accessorPropertiesOnly"].Value<bool>())
{
- objectValuesOpt |= GetObjectCommandOptions.AccessorPropertiesOnly;
- accessorPropertiesOnly = true;
+ getObjectOptions |= GetObjectCommandOptions.AccessorPropertiesOnly;
}
if (args["ownProperties"] != null && args["ownProperties"].Value<bool>())
{
- objectValuesOpt |= GetObjectCommandOptions.OwnProperties;
+ getObjectOptions |= GetObjectCommandOptions.OwnProperties;
}
}
- try {
+ try
+ {
switch (objectId.Scheme)
{
case "scope":
- {
Result resScope = await GetScopeProperties(id, objectId.Value, token);
return resScope.IsOk
- ? ValueOrError<JToken>.WithValue(sortByAccessLevel ? resScope.Value : resScope.Value?["result"])
- : ValueOrError<JToken>.WithError(resScope);
- }
+ ? ValueOrError<GetMembersResult>.WithValue(
+ new GetMembersResult((JArray)resScope.Value?["result"], sortByAccessLevel: false))
+ : ValueOrError<GetMembersResult>.WithError(resScope);
case "valuetype":
- {
- var valType = context.SdbAgent.GetValueTypeClass(objectId.Value);
- if (valType == null)
- return ValueOrError<JToken>.WithError($"Internal Error: No valuetype found for {objectId}.");
- var resValue = await valType.GetValues(context.SdbAgent, accessorPropertiesOnly, token);
+ var resValue = await MemberObjectsExplorer.GetValueTypeMemberValues(
+ context.SdbAgent, objectId.Value, getObjectOptions, token, sortByAccessLevel, includeStatic: false);
return resValue switch
{
- null => ValueOrError<JToken>.WithError($"Could not get properties for {objectId}"),
- _ => ValueOrError<JToken>.WithValue(sortByAccessLevel ? JObject.FromObject(new { result = resValue }) : resValue)
+ null => ValueOrError<GetMembersResult>.WithError($"Could not get properties for {objectId}"),
+ _ => ValueOrError<GetMembersResult>.WithValue(resValue)
};
- }
case "array":
- {
var resArr = await context.SdbAgent.GetArrayValues(objectId.Value, token);
- return ValueOrError<JToken>.WithValue(sortByAccessLevel ? JObject.FromObject(new { result = resArr }) : resArr);
- }
- case "methodId":
- {
- var resMethod = await context.SdbAgent.InvokeMethodInObject(objectId, objectId.SubValue, null, token);
- return ValueOrError<JToken>.WithValue(sortByAccessLevel ? JObject.FromObject(new { result = new JArray(resMethod) }) : new JArray(resMethod));
- }
+ return ValueOrError<GetMembersResult>.WithValue(GetMembersResult.FromValues(resArr));
+ case "method":
+ var resMethod = await context.SdbAgent.InvokeMethod(objectId, token);
+ return ValueOrError<GetMembersResult>.WithValue(GetMembersResult.FromValues(new JArray(resMethod)));
case "object":
- {
- var resObj = await context.SdbAgent.GetObjectValues(objectId.Value, objectValuesOpt, token, sortByAccessLevel);
- return ValueOrError<JToken>.WithValue(sortByAccessLevel ? resObj[0] : resObj);
- }
+ var resObj = await MemberObjectsExplorer.GetObjectMemberValues(
+ context.SdbAgent, objectId.Value, getObjectOptions, token, sortByAccessLevel, includeStatic: true);
+ return ValueOrError<GetMembersResult>.WithValue(resObj);
case "pointer":
- {
var resPointer = new JArray { await context.SdbAgent.GetPointerContent(objectId.Value, token) };
- return ValueOrError<JToken>.WithValue(sortByAccessLevel ? JObject.FromObject(new { result = resPointer }) : resPointer);
- }
+ return ValueOrError<GetMembersResult>.WithValue(GetMembersResult.FromValues(resPointer));
case "cfo_res":
- {
Result res = await SendMonoCommand(id, MonoCommands.GetDetails(RuntimeId, objectId.Value, args), token);
string value_json_str = res.Value["result"]?["value"]?["__value_as_json_string__"]?.Value<string>();
if (res.IsOk && value_json_str == null)
- return ValueOrError<JToken>.WithError($"Internal error: Could not find expected __value_as_json_string__ field in the result: {res}");
+ return ValueOrError<GetMembersResult>.WithError(
+ $"Internal error: Could not find expected __value_as_json_string__ field in the result: {res}");
return value_json_str != null
- ? ValueOrError<JToken>.WithValue(sortByAccessLevel ? JObject.FromObject(new { result = JArray.Parse(value_json_str) }) : JArray.Parse(value_json_str))
- : ValueOrError<JToken>.WithError(res);
- }
+ ? ValueOrError<GetMembersResult>.WithValue(GetMembersResult.FromValues(JArray.Parse(value_json_str)))
+ : ValueOrError<GetMembersResult>.WithError(res);
default:
- return ValueOrError<JToken>.WithError($"RuntimeGetProperties: unknown object id scheme: {objectId.Scheme}");
+ return ValueOrError<GetMembersResult>.WithError($"RuntimeGetProperties: unknown object id scheme: {objectId.Scheme}");
}
}
catch (Exception ex)
{
- return ValueOrError<JToken>.WithError($"RuntimeGetProperties: Failed to get properties for {objectId}: {ex}");
+ return ValueOrError<GetMembersResult>.WithError($"RuntimeGetProperties: Failed to get properties for {objectId}: {ex}");
}
}
string reason = "exception";
int object_id = retDebuggerCmdReader.ReadInt32();
var caught = retDebuggerCmdReader.ReadByte();
- var exceptionObject = await context.SdbAgent.GetObjectValues(object_id, GetObjectCommandOptions.WithProperties | GetObjectCommandOptions.OwnProperties, token);
+ var exceptionObject = await MemberObjectsExplorer.GetObjectMemberValues(
+ context.SdbAgent, object_id, GetObjectCommandOptions.WithProperties | GetObjectCommandOptions.OwnProperties, token);
var exceptionObjectMessage = exceptionObject.FirstOrDefault(attr => attr["name"].Value<string>().Equals("_message"));
var data = JObject.FromObject(new
{
using System.Reflection;
using System.Text;
using System.Runtime.CompilerServices;
-using System.Diagnostics;
+using BrowserDebugProxy;
namespace Microsoft.WebAssembly.Diagnostics
{
public string Name { get; }
public int TypeId { get; }
public bool IsNotPrivate { get; }
- public FieldAttributes ProtectionLevel { get; }
- public FieldTypeClass(int id, string name, int typeId, bool isNotPrivate, FieldAttributes protectionLevel)
+ public bool IsBackingField { get; }
+ public FieldAttributes Attributes { get; }
+ public FieldTypeClass(int id, string name, int typeId, bool isBackingField, FieldAttributes attributes)
{
Id = id;
Name = name;
TypeId = typeId;
- IsNotPrivate = isNotPrivate;
- ProtectionLevel = protectionLevel;
- }
- }
- internal sealed class ValueTypeClass
- {
- private readonly JArray json;
- private readonly int typeId;
- private readonly bool autoExpand;
- private readonly int id;
- private JArray proxy;
- private JArray jsonProps;
-
- public byte[] Buffer { get; }
-
- public ValueTypeClass(byte[] buffer, JArray json, int typeId, bool expand_properties, int valueTypeId)
- {
- Buffer = buffer;
- this.json = json;
- this.typeId = typeId;
- jsonProps = null;
- proxy = null;
- autoExpand = expand_properties;
- id = valueTypeId;
- }
-
- public async Task<JArray> GetProxy(MonoSDBHelper sdbAgent, CancellationToken token)
- {
- if (proxy != null)
- return proxy;
- proxy = new JArray(json);
-
- var retDebuggerCmdReader = await sdbAgent.GetTypePropertiesReader(typeId, token);
- if (retDebuggerCmdReader == null)
- return null;
-
- var nProperties = retDebuggerCmdReader.ReadInt32();
-
- for (int i = 0; i < nProperties; i++)
- {
- retDebuggerCmdReader.ReadInt32(); //propertyId
- string propertyNameStr = retDebuggerCmdReader.ReadString();
-
- var getMethodId = retDebuggerCmdReader.ReadInt32();
- retDebuggerCmdReader.ReadInt32(); //setmethod
- retDebuggerCmdReader.ReadInt32(); //attrs
- if (await sdbAgent.MethodIsStatic(getMethodId, token))
- continue;
- using var command_params_writer_to_proxy = new MonoBinaryWriter();
- command_params_writer_to_proxy.Write(getMethodId);
- command_params_writer_to_proxy.Write(Buffer);
- command_params_writer_to_proxy.Write(0);
- var (data, length) = command_params_writer_to_proxy.ToBase64();
- proxy.Add(JObject.FromObject(new
- {
- get = JObject.FromObject(new
- {
- commandSet = CommandSet.Vm,
- command = CmdVM.InvokeMethod,
- buffer = data,
- length = length,
- id = MonoSDBHelper.GetNewId()
- }),
- name = propertyNameStr
- }));
- }
- return proxy;
- }
-
- public async Task<JArray> GetProperties(MonoSDBHelper sdbAgent, CancellationToken token)
- {
- JArray ret = new JArray();
- using var commandParamsWriter = new MonoBinaryWriter();
- commandParamsWriter.Write(typeId);
- using var retDebuggerCmdReader = await sdbAgent.SendDebuggerAgentCommand(CmdType.GetParents, commandParamsWriter, token);
- var parentsCount = retDebuggerCmdReader.ReadInt32();
- List<int> typesToGetProperties = new List<int>();
- typesToGetProperties.Add(typeId);
- for (int i = 0; i < parentsCount; i++)
- {
- typesToGetProperties.Add(retDebuggerCmdReader.ReadInt32());
- }
- for (int i = 0; i < typesToGetProperties.Count; i++)
- {
- var properties = await sdbAgent.CreateJArrayForProperties(typesToGetProperties[i], ElementType.ValueType, Buffer, json, autoExpand, $"dotnet:valuetype:{id}", i == 0, token);
- ret = new JArray(ret.Union(properties));
- }
- return ret;
- }
-
- public async Task<JArray> GetValues(MonoSDBHelper sdbAgent, bool accessorPropertiesOnly, CancellationToken token)
- {
- if (jsonProps == null)
- jsonProps = await GetProperties(sdbAgent, token);
- if (accessorPropertiesOnly)
- return jsonProps;
- var ret = new JArray(json.Union(jsonProps));
- return ret;
+ IsNotPrivate = (Attributes & FieldAttributes.FieldAccessMask & FieldAttributes.Public) != 0;
+ Attributes = attributes;
+ IsBackingField = isBackingField;
}
}
public long address;
public int typeId;
public string varName;
+ private JObject _value;
+
public PointerValue(long address, int typeId, string varName)
{
this.address = address;
this.varName = varName;
}
+ public async Task<JObject> GetValue(MonoSDBHelper sdbHelper, CancellationToken token)
+ {
+ if (_value == null)
+ {
+ using var commandParamsWriter = new MonoBinaryWriter();
+ commandParamsWriter.Write(address);
+ commandParamsWriter.Write(typeId);
+ using var retDebuggerCmdReader = await sdbHelper.SendDebuggerAgentCommand(CmdPointer.GetValue, commandParamsWriter, token);
+ string displayVarName = varName;
+ if (int.TryParse(varName, out _))
+ displayVarName = $"[{varName}]";
+ _value = await sdbHelper.CreateJObjectForVariableValue(retDebuggerCmdReader, "*" + displayVarName, token);
+ }
+
+ return _value;
+ }
}
internal sealed class MonoSDBHelper
{
private Regex regexForAsyncLocals = new Regex(@"\<([^)]*)\>", RegexOptions.Singleline);
public static int GetNewId() { return cmdId++; }
+ public static int GetNewObjectId() => Interlocked.Increment(ref debuggerObjectId);
public MonoSDBHelper(MonoProxy proxy, ILogger logger, SessionId sessionId)
{
commandParamsWriter.Write(fieldId);
using var retDebuggerCmdReader = await SendDebuggerAgentCommand(CmdType.GetValues, commandParamsWriter, token);
- return await CreateJObjectForVariableValue(retDebuggerCmdReader, "", false, -1, false, token);
+ return await CreateJObjectForVariableValue(retDebuggerCmdReader, "", token);
}
public async Task<int> TypeIsInitialized(int typeId, CancellationToken token)
for (int i = 0 ; i < nFields; i++)
{
- bool isNotPrivate = false;
int fieldId = retDebuggerCmdReader.ReadInt32(); //fieldId
string fieldNameStr = retDebuggerCmdReader.ReadString();
int fieldTypeId = retDebuggerCmdReader.ReadInt32(); //typeId
int attrs = retDebuggerCmdReader.ReadInt32(); //attrs
+ FieldAttributes fieldAttrs = (FieldAttributes)attrs;
int isSpecialStatic = retDebuggerCmdReader.ReadInt32(); //is_special_static
- if (((attrs & (int)MethodAttributes.Public) != 0))
- isNotPrivate = true;
if (isSpecialStatic == 1)
continue;
+
+ bool isBackingField = false;
if (fieldNameStr.Contains("k__BackingField"))
{
+ isBackingField = true;
fieldNameStr = fieldNameStr.Replace("k__BackingField", "");
fieldNameStr = fieldNameStr.Replace("<", "");
fieldNameStr = fieldNameStr.Replace(">", "");
}
- ret.Add(new FieldTypeClass(fieldId, fieldNameStr, fieldTypeId, isNotPrivate, (FieldAttributes)((attrs) & (int)FieldAttributes.FieldAccessMask)));
+ ret.Add(new FieldTypeClass(fieldId, fieldNameStr, fieldTypeId, isBackingField, fieldAttrs));
}
typeInfo.FieldsList = ret;
return ret;
//.Replace("System.Decimal", "decimal")
.ToString();
- internal async Task<MonoBinaryReader> GetCAttrsFromType(int objectId, int typeId, string attrName, CancellationToken token)
+ internal async Task<MonoBinaryReader> GetCAttrsFromType(int typeId, string attrName, CancellationToken token)
{
using var commandParamsWriter = new MonoBinaryWriter();
commandParamsWriter.Write(typeId);
for (int j = 0; j < parmCount; j++)
{
//to typed_args
- await CreateJObjectForVariableValue(retDebuggerCmdReader, "varName", false, -1, false, token);
+ await CreateJObjectForVariableValue(retDebuggerCmdReader, "varName", token);
}
}
}
return retDebuggerCmdReader.ReadInt32();
}
- public async Task<string> GetValueFromDebuggerDisplayAttribute(int objectId, int typeId, CancellationToken token)
+ public async Task<string> GetValueFromDebuggerDisplayAttribute(DotnetObjectId dotnetObjectId, int typeId, CancellationToken token)
{
string expr = "";
try {
- var getCAttrsRetReader = await GetCAttrsFromType(objectId, typeId, "System.Diagnostics.DebuggerDisplayAttribute", token);
+ var getCAttrsRetReader = await GetCAttrsFromType(typeId, "System.Diagnostics.DebuggerDisplayAttribute", token);
if (getCAttrsRetReader == null)
return null;
var parmCount = getCAttrsRetReader.ReadInt32();
- var monoType = (ElementType) getCAttrsRetReader.ReadByte(); //MonoTypeEnum -> MONO_TYPE_STRING
+ var monoType = (ElementType)getCAttrsRetReader.ReadByte(); //MonoTypeEnum -> MONO_TYPE_STRING
if (monoType != ElementType.String)
return null;
var stringId = getCAttrsRetReader.ReadInt32();
var dispAttrStr = await GetStringValue(stringId, token);
ExecutionContext context = proxy.GetContext(sessionId);
- JArray objectValues = await GetObjectValues(objectId, GetObjectCommandOptions.WithProperties | GetObjectCommandOptions.ForDebuggerDisplayAttribute, token);
+ GetMembersResult members = await GetTypeMemberValues(
+ dotnetObjectId,
+ GetObjectCommandOptions.WithProperties | GetObjectCommandOptions.ForDebuggerDisplayAttribute,
+ token);
+ JArray objectValues = new JArray(members.Flatten());
- var thisObj = CreateJObject<string>(value: "", type: "object", description: "", writable: false, objectId: $"dotnet:object:{objectId}");
+ var thisObj = CreateJObject<string>(value: "", type: "object", description: "", writable: false, objectId: dotnetObjectId.ToString());
thisObj["name"] = "this";
objectValues.Add(thisObj);
}
return new ArrayDimensions(rank);
}
- public async Task<List<int>> GetTypeIdFromObject(int object_id, bool withParents, CancellationToken token)
+
+ public async Task<List<int>> GetTypeIdsForObject(int object_id, bool withParents, CancellationToken token)
{
List<int> ret = new List<int>();
using var commandParamsWriter = new MonoBinaryWriter();
public async Task<string> GetClassNameFromObject(int object_id, CancellationToken token)
{
- var type_id = await GetTypeIdFromObject(object_id, false, token);
+ var type_id = await GetTypeIdsForObject(object_id, false, token);
return await GetTypeName(type_id[0], token);
}
return $"{returnType} {methodName} {parameters}";
}
- public async Task<JObject> InvokeMethod(ArraySegment<byte> valueTypeBuffer, int methodId, string varName, CancellationToken token)
+
+ public async Task<JObject> InvokeMethod(ArraySegment<byte> argsBuffer, int methodId, CancellationToken token, string name = null)
{
using var commandParamsWriter = new MonoBinaryWriter();
commandParamsWriter.Write(methodId);
- commandParamsWriter.Write(valueTypeBuffer);
+ commandParamsWriter.Write(argsBuffer);
commandParamsWriter.Write(0);
using var retDebuggerCmdReader = await SendDebuggerAgentCommand(CmdVM.InvokeMethod, commandParamsWriter, token);
retDebuggerCmdReader.ReadByte(); //number of objects returned.
- return await CreateJObjectForVariableValue(retDebuggerCmdReader, varName, false, -1, false, token);
+ return await CreateJObjectForVariableValue(retDebuggerCmdReader, name, token);
+ }
+
+ public Task<JObject> InvokeMethod(int objectId, int methodId, bool isValueType, CancellationToken token)
+ {
+ if (isValueType)
+ {
+ return valueTypes.TryGetValue(objectId, out var valueType)
+ ? InvokeMethod(valueType.Buffer, methodId, token)
+ : throw new ArgumentException($"Could not find valuetype with id {objectId}, for method id: {methodId}", nameof(objectId));
+ }
+ else
+ {
+ using var commandParamsObjWriter = new MonoBinaryWriter();
+ commandParamsObjWriter.Write(ElementType.Class, objectId);
+ return InvokeMethod(commandParamsObjWriter.GetParameterBuffer(), methodId, token);
+ }
}
- public async Task<JObject> InvokeMethodInObject(DotnetObjectId objectId, int methodId, string varName, CancellationToken token)
+ public Task<JObject> InvokeMethod(DotnetObjectId dotnetObjectId, CancellationToken token, int methodId = -1)
{
- if (objectId.IsValueType && valueTypes.TryGetValue(objectId.Value, out var valueType))
- return await InvokeMethod(valueType.Buffer, methodId, varName, token);
- using var commandParamsObjWriter = new MonoBinaryWriter();
- commandParamsObjWriter.Write(ElementType.Class, objectId.Value);
- return await InvokeMethod(commandParamsObjWriter.GetParameterBuffer(), methodId, varName, token);
+ if (dotnetObjectId.Scheme == "method")
+ {
+ JObject args = dotnetObjectId.ValueAsJson;
+ int? objectId = args["containerId"]?.Value<int>();
+ int? embeddedMethodId = args["methodId"]?.Value<int>();
+
+ return objectId == null || embeddedMethodId == null
+ ? throw new ArgumentException($"Invalid object id for a method, with missing container, or methodId", nameof(dotnetObjectId))
+ : InvokeMethod(objectId.Value, embeddedMethodId.Value, isValueType: args["isValueType"]?.Value<bool>() == true, token);
+ }
+
+ return dotnetObjectId.Scheme is "object" or "valuetype"
+ ? InvokeMethod(dotnetObjectId.Value, methodId, isValueType: dotnetObjectId.IsValueType, token)
+ : throw new ArgumentException($"Cannot invoke method with id {methodId} on {dotnetObjectId}", nameof(dotnetObjectId));
}
public async Task<int> GetPropertyMethodIdByName(int typeId, string propertyName, CancellationToken token)
return -1;
}
- public async Task<JArray> CreateJArrayForProperties(int typeId, ElementType elementType, ArraySegment<byte> object_buffer, JArray attributes, bool isAutoExpandable, string objectIdStr, bool isOwn, CancellationToken token)
- {
- JArray ret = new JArray();
- using var retDebuggerCmdReader = await GetTypePropertiesReader(typeId, token);
- if (retDebuggerCmdReader == null)
- return null;
- if (!DotnetObjectId.TryParse(objectIdStr, out DotnetObjectId objectId))
- return null;
- var nProperties = retDebuggerCmdReader.ReadInt32();
- for (int i = 0 ; i < nProperties; i++)
- {
- retDebuggerCmdReader.ReadInt32(); //propertyId
- string propertyNameStr = retDebuggerCmdReader.ReadString();
- var getMethodId = retDebuggerCmdReader.ReadInt32();
- retDebuggerCmdReader.ReadInt32(); //setmethod
- var attrs = retDebuggerCmdReader.ReadInt32(); //attrs
- if (getMethodId == 0 || await GetParamCount(getMethodId, token) != 0 || await MethodIsStatic(getMethodId, token))
- continue;
- JObject propRet = null;
- if (attributes.Where(attribute => attribute["name"].Value<string>().Equals(propertyNameStr)).Any())
- continue;
- if (isAutoExpandable)
- {
- try {
- propRet = await InvokeMethod(object_buffer, getMethodId, propertyNameStr, token);
- }
- catch (Exception)
- {
- continue;
- }
- }
- else
- {
- propRet = JObject.FromObject(new {
- get = new
- {
- type = "function",
- objectId = $"dotnet:methodId:{objectId.Value}:{getMethodId}:{elementType}",
- className = "Function",
- description = "get " + propertyNameStr + " ()",
- methodId = getMethodId,
- objectIdValue = objectIdStr
- },
- name = propertyNameStr
- });
- }
- if (isOwn)
- propRet["isOwn"] = true;
- ret.Add(propRet);
- }
- return ret;
- }
public async Task<JObject> GetPointerContent(int pointerId, CancellationToken token)
{
- using var commandParamsWriter = new MonoBinaryWriter();
- commandParamsWriter.Write(pointerValues[pointerId].address);
- commandParamsWriter.Write(pointerValues[pointerId].typeId);
- using var retDebuggerCmdReader = await SendDebuggerAgentCommand(CmdPointer.GetValue, commandParamsWriter, token);
- var varName = pointerValues[pointerId].varName;
- if (int.TryParse(varName, out _))
- varName = $"[{varName}]";
- return await CreateJObjectForVariableValue(retDebuggerCmdReader, "*" + varName, false, -1, false, token);
+ if (!pointerValues.TryGetValue(pointerId, out PointerValue pointerValue))
+ throw new ArgumentException($"Could not find any pointer with id: {pointerId}", nameof(pointerId));
+
+ return await pointerValue.GetValue(this, token);
}
public static bool AutoExpandable(string className) {
return false;
}
- private static JObject CreateJObject<T>(T value, string type, string description, bool writable, string className = null, string objectId = null, string __custom_type = null, string subtype = null, bool isValueType = false, bool expanded = false, bool isEnum = false)
+ public static JObject CreateJObject<T>(T value, string type, string description, bool writable, string className = null, string objectId = null, string __custom_type = null, string subtype = null, bool isValueType = false, bool expanded = false, bool isEnum = false)
{
var ret = JObject.FromObject(new {
value = new
int pointerId = -1;
if (valueAddress != 0 && className != "(void*)")
{
- pointerId = Interlocked.Increment(ref debuggerObjectId);
+ pointerId = GetNewObjectId();
type = "object";
value = className;
pointerValues[pointerId] = new PointerValue(valueAddress, typeId, name);
public async Task<JObject> CreateJObjectForObject(MonoBinaryReader retDebuggerCmdReader, int typeIdFromAttribute, bool forDebuggerDisplayAttribute, CancellationToken token)
{
var objectId = retDebuggerCmdReader.ReadInt32();
- var type_id = await GetTypeIdFromObject(objectId, false, token);
+ var type_id = await GetTypeIdsForObject(objectId, false, token);
string className = await GetTypeName(type_id[0], token);
string debuggerDisplayAttribute = null;
if (!forDebuggerDisplayAttribute)
- debuggerDisplayAttribute = await GetValueFromDebuggerDisplayAttribute(objectId, type_id[0], token);
+ debuggerDisplayAttribute = await GetValueFromDebuggerDisplayAttribute(new DotnetObjectId("object", objectId), type_id[0], token);
var description = className.ToString();
if (debuggerDisplayAttribute != null)
if (await IsDelegate(objectId, token))
{
if (typeIdFromAttribute != -1)
- {
className = await GetTypeName(typeIdFromAttribute, token);
- }
description = await GetDelegateMethodDescription(objectId, token);
if (description == "")
- {
return CreateJObject<string>(className.ToString(), "symbol", className.ToString(), false);
- }
}
return CreateJObject<string>(null, "object", description, false, className, $"dotnet:object:{objectId}");
}
- public async Task<JObject> CreateJObjectForValueType(MonoBinaryReader retDebuggerCmdReader, string name, long initialPos, CancellationToken token)
+ private static readonly string[] s_primitiveTypeNames = new[]
{
- JObject fieldValueType = null;
- var isEnum = retDebuggerCmdReader.ReadByte();
+ "bool",
+ "char",
+ "string",
+ "byte",
+ "sbyte",
+ "int",
+ "uint",
+ "long",
+ "ulong",
+ "short",
+ "ushort",
+ "float",
+ "double",
+ };
+
+ public static bool IsPrimitiveType(string simplifiedClassName)
+ => s_primitiveTypeNames.Contains(simplifiedClassName);
+
+ public async Task<JObject> CreateJObjectForValueType(
+ MonoBinaryReader retDebuggerCmdReader, string name, long initialPos, bool forDebuggerDisplayAttribute, CancellationToken token)
+ {
+ // FIXME: debugger proxy
+ var isEnum = retDebuggerCmdReader.ReadByte() == 1;
var isBoxed = retDebuggerCmdReader.ReadByte() == 1;
var typeId = retDebuggerCmdReader.ReadInt32();
var className = await GetTypeName(typeId, token);
- var description = className;
- var numFields = retDebuggerCmdReader.ReadInt32();
- var fields = await GetTypeFields(typeId, token);
- JArray valueTypeFields = new JArray();
- if (className.IndexOf("System.Nullable<") == 0) //should we call something on debugger-agent to check???
+ var numValues = retDebuggerCmdReader.ReadInt32();
+
+ if (className.IndexOf("System.Nullable<", StringComparison.Ordinal) == 0) //should we call something on debugger-agent to check???
{
retDebuggerCmdReader.ReadByte(); //ignoring the boolean type
var isNull = retDebuggerCmdReader.ReadInt32();
- var value = await CreateJObjectForVariableValue(retDebuggerCmdReader, name, false, -1, false, token);
+
+ // Read the value, even if isNull==true, to correctly advance the reader
+ var value = await CreateJObjectForVariableValue(retDebuggerCmdReader, name, token);
if (isNull != 0)
return value;
else
return CreateJObject<string>(null, "object", className, false, className, null, null, "null", true);
}
- for (int i = 0; i < numFields ; i++)
+ if (isBoxed && numValues == 1)
{
- fieldValueType = await CreateJObjectForVariableValue(retDebuggerCmdReader, fields.ElementAt(i).Name, true, fields.ElementAt(i).TypeId, false, token);
- valueTypeFields.Add(fieldValueType);
+ if (IsPrimitiveType(className))
+ {
+ var value = await CreateJObjectForVariableValue(retDebuggerCmdReader, name: null, token);
+ return value;
+ }
}
- long endPos = retDebuggerCmdReader.BaseStream.Position;
- var valueTypeId = Interlocked.Increment(ref debuggerObjectId);
-
- retDebuggerCmdReader.BaseStream.Position = initialPos;
- byte[] valueTypeBuffer = new byte[endPos - initialPos];
- retDebuggerCmdReader.Read(valueTypeBuffer, 0, (int)(endPos - initialPos));
- retDebuggerCmdReader.BaseStream.Position = endPos;
- valueTypes[valueTypeId] = new ValueTypeClass(valueTypeBuffer, valueTypeFields, typeId, AutoExpandable(className), valueTypeId);
- if (AutoInvokeToString(className) || isEnum == 1) {
- int methodId = await GetMethodIdByName(typeId, "ToString", token);
- var retMethod = await InvokeMethod(valueTypeBuffer, methodId, "methodRet", token);
- description = retMethod["value"]?["value"].Value<string>();
- if (className.Equals("System.Guid"))
- description = description.ToUpperInvariant(); //to keep the old behavior
- }
- else if (isBoxed && numFields == 1) {
- return fieldValueType;
- }
- return CreateJObject<string>(null, "object", description, false, className, $"dotnet:valuetype:{valueTypeId}", null, null, true, true, isEnum == 1);
+ ValueTypeClass valueType = await ValueTypeClass.CreateFromReader(
+ this,
+ retDebuggerCmdReader,
+ initialPos,
+ className,
+ typeId,
+ numValues,
+ isEnum,
+ token);
+ valueTypes[valueType.Id.Value] = valueType;
+ return await valueType.ToJObject(this, forDebuggerDisplayAttribute, token);
}
public async Task<JObject> CreateJObjectForNull(MonoBinaryReader retDebuggerCmdReader, CancellationToken token)
return CreateJObject<string>(null, "object", className, false, className, null, null, "null");
}
- public async Task<JObject> CreateJObjectForVariableValue(MonoBinaryReader retDebuggerCmdReader, string name, bool isOwn, int typeIdFromAttribute, bool forDebuggerDisplayAttribute, CancellationToken token)
+ public async Task<JObject> CreateJObjectForVariableValue(MonoBinaryReader retDebuggerCmdReader,
+ string name,
+ CancellationToken token,
+ bool isOwn = false,
+ int typeIdForObject = -1,
+ bool forDebuggerDisplayAttribute = false)
{
- long initialPos = retDebuggerCmdReader == null ? 0 : retDebuggerCmdReader.BaseStream.Position;
+ long initialPos = /*retDebuggerCmdReader == null ? 0 : */retDebuggerCmdReader.BaseStream.Position;
ElementType etype = (ElementType)retDebuggerCmdReader.ReadByte();
JObject ret = null;
switch (etype) {
case ElementType.Class:
case ElementType.Object:
{
- ret = await CreateJObjectForObject(retDebuggerCmdReader, typeIdFromAttribute, forDebuggerDisplayAttribute, token);
+ ret = await CreateJObjectForObject(retDebuggerCmdReader, typeIdForObject, forDebuggerDisplayAttribute, token);
break;
}
case ElementType.ValueType:
{
- ret = await CreateJObjectForValueType(retDebuggerCmdReader, name, initialPos, token);
+ ret = await CreateJObjectForValueType(retDebuggerCmdReader, name, initialPos, forDebuggerDisplayAttribute, token);
break;
}
case (ElementType)ValueTypeId.Null:
{
if (isOwn)
ret["isOwn"] = true;
- ret["name"] = name;
+ if (!string.IsNullOrEmpty(name))
+ ret["name"] = name;
}
return ret;
}
fieldName.StartsWith ("<>8__", StringComparison.Ordinal);
}
- public async Task<JArray> GetHoistedLocalVariables(int objectId, JArray asyncLocals, CancellationToken token)
+ public async Task<JArray> GetHoistedLocalVariables(int objectId, IEnumerable<JToken> asyncLocals, CancellationToken token)
{
JArray asyncLocalsFull = new JArray();
List<int> objectsAlreadyRead = new();
{
if (!objectsAlreadyRead.Contains(dotnetObjectId.Value))
{
- var asyncLocalsFromObject = await GetObjectValues(dotnetObjectId.Value, GetObjectCommandOptions.WithProperties, token);
- var hoistedLocalVariable = await GetHoistedLocalVariables(dotnetObjectId.Value, asyncLocalsFromObject, token);
+ var asyncProxyMembersFromObject = await MemberObjectsExplorer.GetObjectMemberValues(
+ this, dotnetObjectId.Value, GetObjectCommandOptions.WithProperties, token);
+ var hoistedLocalVariable = await GetHoistedLocalVariables(dotnetObjectId.Value, asyncProxyMembersFromObject.Flatten(), token);
asyncLocalsFull = new JArray(asyncLocalsFull.Union(hoistedLocalVariable));
}
}
using var retDebuggerCmdReader = await SendDebuggerAgentCommand(CmdFrame.GetThis, commandParamsWriter, token);
retDebuggerCmdReader.ReadByte(); //ignore type
var objectId = retDebuggerCmdReader.ReadInt32();
- var asyncLocals = await GetObjectValues(objectId, GetObjectCommandOptions.WithProperties, token);
- asyncLocals = await GetHoistedLocalVariables(objectId, asyncLocals, token);
+ GetMembersResult asyncProxyMembers = await MemberObjectsExplorer.GetObjectMemberValues(this, objectId, GetObjectCommandOptions.WithProperties, token);
+ var asyncLocals = await GetHoistedLocalVariables(objectId, asyncProxyMembers.Flatten(), token);
return asyncLocals;
}
{
try
{
- var var_json = await CreateJObjectForVariableValue(localsDebuggerCmdReader, var.Name, false, -1, false, token);
+ var var_json = await CreateJObjectForVariableValue(localsDebuggerCmdReader, var.Name, token);
locals.Add(var_json);
}
catch (Exception ex)
if (!method.Info.IsStatic())
{
using var retDebuggerCmdReader = await SendDebuggerAgentCommand(CmdFrame.GetThis, commandParamsWriter, token);
- var var_json = await CreateJObjectForVariableValue(retDebuggerCmdReader, "this", false, -1, false, token);
+ var var_json = await CreateJObjectForVariableValue(retDebuggerCmdReader, "this", token);
var_json.Add("fieldOffset", -1);
locals.Add(var_json);
}
JArray array = new JArray();
for (int i = 0 ; i < dimensions.TotalLength; i++)
{
- var var_json = await CreateJObjectForVariableValue(retDebuggerCmdReader, dimensions.GetArrayIndexString(i), isOwn : false, -1, forDebuggerDisplayAttribute : false, token);
+ var var_json = await CreateJObjectForVariableValue(retDebuggerCmdReader, dimensions.GetArrayIndexString(i), token);
array.Add(var_json);
}
return array;
return retDebuggerCmdReader.ReadInt32();
}
- public async Task<JArray> GetValuesFromDebuggerProxyAttribute(int objectId, int typeId, CancellationToken token)
+ // FIXME: support valuetypes
+ public async Task<GetMembersResult> GetValuesFromDebuggerProxyAttribute(int objectId, int typeId, CancellationToken token)
{
- try {
- var getCAttrsRetReader = await GetCAttrsFromType(objectId, typeId, "System.Diagnostics.DebuggerTypeProxyAttribute", token);
- var methodId = -1;
- if (getCAttrsRetReader == null)
+ try
+ {
+ int methodId = await FindDebuggerProxyConstructorIdFor(typeId, token);
+ if (methodId == -1)
+ {
+ logger.LogInformation($"GetValuesFromDebuggerProxyAttribute: could not find proxy constructor id for objectId {objectId}");
return null;
- using var invokeParamsWriter = new MonoBinaryWriter();
- invokeParamsWriter.Write((byte)ValueTypeId.Null);
- invokeParamsWriter.Write((byte)0); //not used
- invokeParamsWriter.Write(0); //not used
+ }
+
+ using var ctorArgsWriter = new MonoBinaryWriter();
+ ctorArgsWriter.Write((byte)ValueTypeId.Null);
+
+ // FIXME: move method invocation to valueTypeclass?
+ if (valueTypes.TryGetValue(objectId, out var valueType))
+ {
+ //FIXME: Issue #68390
+ //ctorArgsWriter.Write((byte)0); //not used but needed
+ //ctorArgsWriter.Write(0); //not used but needed
+ //ctorArgsWriter.Write((int)1); // num args
+ //ctorArgsWriter.Write(valueType.Buffer);
+ return null;
+ }
+ else
+ {
+ ctorArgsWriter.Write((byte)0); //not used
+ ctorArgsWriter.Write(0); //not used
+ ctorArgsWriter.Write((int)1); // num args
+ ctorArgsWriter.Write((byte)ElementType.Object);
+ ctorArgsWriter.Write(objectId);
+ }
+
+ var retMethod = await InvokeMethod(ctorArgsWriter.GetParameterBuffer(), methodId, token);
+ logger.LogInformation($"* GetValuesFromDebuggerProxyAttribute got from InvokeMethod: {retMethod}");
+ if (!DotnetObjectId.TryParse(retMethod?["value"]?["objectId"]?.Value<string>(), out DotnetObjectId dotnetObjectId))
+ throw new Exception($"Invoking .ctor ({methodId}) for DebuggerTypeProxy on type {typeId} returned {retMethod}");
+
+ GetMembersResult members = await GetTypeMemberValues(dotnetObjectId,
+ GetObjectCommandOptions.WithProperties | GetObjectCommandOptions.ForDebuggerProxyAttribute,
+ token);
+
+ return members;
+ }
+ catch (Exception e)
+ {
+ logger.LogInformation($"Could not evaluate DebuggerTypeProxyAttribute of type {await GetTypeName(typeId, token)} - {e}");
+ }
+
+ return null;
+ }
+
+ private async Task<int> FindDebuggerProxyConstructorIdFor(int typeId, CancellationToken token)
+ {
+ try
+ {
+ var getCAttrsRetReader = await GetCAttrsFromType(typeId, "System.Diagnostics.DebuggerTypeProxyAttribute", token);
+ if (getCAttrsRetReader == null)
+ return -1;
+
+ var methodId = -1;
var parmCount = getCAttrsRetReader.ReadInt32();
- invokeParamsWriter.Write((int)1);
for (int j = 0; j < parmCount; j++)
{
var monoTypeId = getCAttrsRetReader.ReadByte();
+ // FIXME: DebuggerTypeProxyAttribute(string) - not supported
if ((ValueTypeId)monoTypeId != ValueTypeId.Type)
continue;
+
var cAttrTypeId = getCAttrsRetReader.ReadInt32();
using var commandParamsWriter = new MonoBinaryWriter();
commandParamsWriter.Write(cAttrTypeId);
var assemblyIdArg = await GetAssemblyIdFromType(genericTypeArgs[k], token);
var assemblyNameArg = await GetFullAssemblyName(assemblyIdArg, token);
var classNameArg = await GetTypeNameOriginal(genericTypeArgs[k], token);
- typeToSearch += classNameArg +", " + assemblyNameArg;
+ typeToSearch += classNameArg + ", " + assemblyNameArg;
if (k + 1 < genericTypeArgs.Count)
typeToSearch += "], [";
else
typeToSearch += "]";
}
typeToSearch += "]";
- typeToSearch += ", " + assemblyName;
+ typeToSearch += ", " + assemblyName;
var genericTypeId = await GetTypeByName(typeToSearch, token);
if (genericTypeId < 0)
- return null;
- methodId = await GetMethodIdByName(genericTypeId, ".ctor", token);
+ break;
+ cAttrTypeId = genericTypeId;
}
- else
- methodId = await GetMethodIdByName(cAttrTypeId, ".ctor", token);
- invokeParamsWriter.Write((byte)ElementType.Object);
- invokeParamsWriter.Write(objectId);
-
- var retMethod = await InvokeMethod(invokeParamsWriter.GetParameterBuffer(), methodId, "methodRet", token);
- DotnetObjectId.TryParse(retMethod?["value"]?["objectId"]?.Value<string>(), out DotnetObjectId dotnetObjectId);
- var displayAttrs = await GetObjectValues(dotnetObjectId.Value, GetObjectCommandOptions.WithProperties | GetObjectCommandOptions.ForDebuggerProxyAttribute, token);
- return displayAttrs;
+ methodId = await GetMethodIdByName(cAttrTypeId, ".ctor", token);
+ break;
}
+
+ return methodId;
}
catch (Exception e)
{
logger.LogDebug($"Could not evaluate DebuggerTypeProxyAttribute of type {await GetTypeName(typeId, token)} - {e}");
}
- return null;
- }
-
- public async Task<JArray> GetObjectValues(int objectId, GetObjectCommandOptions getCommandType, CancellationToken token, bool sortByAccessLevel = false)
- {
- var typeIdsIncludingParents = await GetTypeIdFromObject(objectId, true, token);
- if (!getCommandType.HasFlag(GetObjectCommandOptions.ForDebuggerDisplayAttribute))
- {
- var debuggerProxy = await GetValuesFromDebuggerProxyAttribute(objectId, typeIdsIncludingParents[0], token);
- if (debuggerProxy != null)
- return sortByAccessLevel ?
- new JArray(JObject.FromObject( new { result = debuggerProxy, internalProperties = new JArray(), privateProperties = new JArray() } )) :
- debuggerProxy;
- }
- if (await IsDelegate(objectId, token))
- {
- var description = await GetDelegateMethodDescription(objectId, token);
- var objValues = new JArray(JObject.FromObject(new
- {
- value = new
- {
- type = "symbol",
- value = description,
- description
- },
- name = "Target"
- }));
- return sortByAccessLevel ?
- new JArray(JObject.FromObject(new { result = objValues, internalProperties = new JArray(), privateProperties = new JArray() })) :
- objValues;
- }
- var allFields = new List<FieldTypeClass>();
- var objects = new Dictionary<string, JToken>();
- for (int i = 0; i < typeIdsIncludingParents.Count; i++)
- {
- int typeId = typeIdsIncludingParents[i];
- // 0th id is for the object itself, and then its parents
- bool isOwn = i == 0;
- var fields = await GetTypeFields(typeId, token);
- allFields.AddRange(fields);
-
- if (!getCommandType.HasFlag(GetObjectCommandOptions.AccessorPropertiesOnly))
- {
- var (collapsedFields, rootHiddenFields) = await FilterFieldsByDebuggerBrowsable(fields, typeId, token);
-
- var collapsedFieldsValues = await GetFieldsValues(collapsedFields, isOwn);
- var hiddenFieldsValues = await GetFieldsValues(rootHiddenFields, isOwn, isRootHidden: true);
-
- objects.TryAddRange(collapsedFieldsValues);
- objects.TryAddRange(hiddenFieldsValues);
- }
-
- if (!getCommandType.HasFlag(GetObjectCommandOptions.WithProperties))
- return sortByAccessLevel ?
- SegregatePropertiesByAccessLevel(allFields, objects, token) :
- new JArray(objects.Values);
-
- using var commandParamsObjWriter = new MonoBinaryWriter();
- commandParamsObjWriter.WriteObj(new DotnetObjectId("object", objectId), this);
- var props = await CreateJArrayForProperties(
- typeId,
- ElementType.Class,
- commandParamsObjWriter.GetParameterBuffer(),
- new JArray(objects.Values),
- getCommandType.HasFlag(GetObjectCommandOptions.ForDebuggerProxyAttribute),
- $"dotnet:object:{objectId}",
- i == 0,
- token);
- var properties = await GetProperties(props, allFields, typeId, token);
- objects.TryAddRange(properties);
-
- // ownProperties
- // Note: ownProperties should mean that we return members of the klass itself,
- // but we are going to ignore that here, because otherwise vscode/chrome don't
- // seem to ask for inherited fields at all.
- //if (ownProperties)
- //break;
- /*if (accessorPropertiesOnly)
- break;*/
- }
- return sortByAccessLevel ?
- SegregatePropertiesByAccessLevel(allFields, objects, token) :
- new JArray(objects.Values);
-
- JArray SegregatePropertiesByAccessLevel(List<FieldTypeClass> fields, Dictionary<string, JToken> objectsDict, CancellationToken token)
- {
- if (fields.Count == 0)
- return new JArray(JObject.FromObject(new { result = new JArray(objectsDict.Values) }));
-
- var pubNames = fields.Where(field => field.ProtectionLevel == FieldAttributes.Public)
- .Select(field => field.Name).ToList();
- var privNames = fields.Where(field =>
- (field.ProtectionLevel == FieldAttributes.Private ||
- field.ProtectionLevel == FieldAttributes.FamANDAssem) &&
- // when field is inherited it is listed both in Private and Public, to avoid duplicates:
- pubNames.All(pubFieldName => pubFieldName != field.Name))
- .Select(field => field.Name).ToList();
- //protected == family, internal == assembly
- var protectedAndInternalNames = fields.Where(field =>
- field.ProtectionLevel == FieldAttributes.Family ||
- field.ProtectionLevel == FieldAttributes.Assembly ||
- field.ProtectionLevel == FieldAttributes.FamORAssem)
- .Select(field => field.Name).ToList();
- var accessorProperties = objectsDict
- .Where(obj => (
- pubNames.All(name => name != obj.Key) &&
- privNames.All(name => name != obj.Key) &&
- protectedAndInternalNames.All(name => name != obj.Key)))
- .Select((k, v) => k.Value);
-
- var pubProperties = objectsDict.GetValuesByKeys(pubNames);
- var privProperties = objectsDict.GetValuesByKeys(privNames);
- var protAndIntProperties = objectsDict.GetValuesByKeys(protectedAndInternalNames);
- pubProperties.AddRange(new JArray(accessorProperties));
-
- return new JArray(JObject.FromObject(new
- {
- result = pubProperties,
- internalProperties = protAndIntProperties,
- privateProperties = privProperties
- }));
- }
-
- async Task AppendRootHiddenChildren(JObject root, JArray expandedCollection)
- {
- if (!DotnetObjectId.TryParse(root?["value"]?["objectId"]?.Value<string>(), out DotnetObjectId rootHiddenObjectId))
- return;
-
- var resultValue = new JArray();
- // collections require extracting items to get inner values; items are of array type
- // arrays have "subtype": "array" field, collections don't
- var subtype = root?["value"]?["subtype"];
- var rootHiddenObjectIdInt = rootHiddenObjectId.Value;
- if (subtype == null || subtype?.Value<string>() != "array")
- {
- resultValue = await GetObjectValues(rootHiddenObjectIdInt, getCommandType, token);
- DotnetObjectId.TryParse(resultValue[0]?["value"]?["objectId"]?.Value<string>(), out DotnetObjectId objectId2);
- rootHiddenObjectIdInt = objectId2.Value;
- }
- resultValue = await GetArrayValues(rootHiddenObjectIdInt, token);
-
- // root hidden item name has to be unique, so we concatenate the root's name to it
- foreach (var item in resultValue)
- {
- item["name"] = string.Concat(root["name"], "[", item["name"], "]");
- expandedCollection.Add(item);
- }
- }
-
- async Task<JArray> GetFieldsValues(List<FieldTypeClass> fields, bool isOwn, bool isRootHidden = false)
- {
- JArray objFields = new JArray();
- if (fields.Count == 0)
- return objFields;
- if (getCommandType.HasFlag(GetObjectCommandOptions.ForDebuggerProxyAttribute))
- fields = fields.Where(field => field.IsNotPrivate).ToList();
-
- using var commandParamsWriter = new MonoBinaryWriter();
- commandParamsWriter.Write(objectId);
- commandParamsWriter.Write(fields.Count);
- foreach (var field in fields)
- commandParamsWriter.Write(field.Id);
- var retDebuggerCmdReader = await SendDebuggerAgentCommand(CmdObject.RefGetValues, commandParamsWriter, token);
-
- foreach (var field in fields)
- {
- long initialPos = retDebuggerCmdReader.BaseStream.Position;
- int valtype = retDebuggerCmdReader.ReadByte();
- retDebuggerCmdReader.BaseStream.Position = initialPos;
- var fieldValue = await CreateJObjectForVariableValue(retDebuggerCmdReader, field.Name, isOwn: isOwn, field.TypeId, getCommandType.HasFlag(GetObjectCommandOptions.ForDebuggerDisplayAttribute), token);
- if (objects.Where((k, v) => k.Equals(fieldValue["name"].Value<string>())).Any())
- continue;
- if (getCommandType.HasFlag(GetObjectCommandOptions.WithSetter))
- {
- var command_params_writer_to_set = new MonoBinaryWriter();
- command_params_writer_to_set.Write(objectId);
- command_params_writer_to_set.Write(1);
- command_params_writer_to_set.Write(field.Id);
- var (data, length) = command_params_writer_to_set.ToBase64();
+ return -1;
+ }
- fieldValue.Add("set", JObject.FromObject(new
- {
- commandSet = CommandSet.ObjectRef,
- command = CmdObject.RefSetValues,
- buffer = data,
- valtype,
- length,
- id = GetNewId()
- }));
- }
- if (!isRootHidden)
- {
- objFields.Add(fieldValue);
- continue;
- }
- await AppendRootHiddenChildren(fieldValue, objFields);
- }
- return objFields;
- }
+ public Task<GetMembersResult> GetTypeMemberValues(DotnetObjectId dotnetObjectId, GetObjectCommandOptions getObjectOptions, CancellationToken token, bool sortByAccessLevel = false)
+ => dotnetObjectId.IsValueType
+ ? MemberObjectsExplorer.GetValueTypeMemberValues(this, dotnetObjectId.Value, getObjectOptions, token)
+ : MemberObjectsExplorer.GetObjectMemberValues(this, dotnetObjectId.Value, getObjectOptions, token);
- async Task<(List<FieldTypeClass>, List<FieldTypeClass>)> FilterFieldsByDebuggerBrowsable(List<FieldTypeClass> fields, int typeId, CancellationToken token)
- {
- if (fields.Count == 0)
- return (fields, new List<FieldTypeClass>());
-
- var typeInfo = await GetTypeInfo(typeId, token);
- var typeFieldsBrowsableInfo = typeInfo?.Info?.DebuggerBrowsableFields;
- var typeProperitesBrowsableInfo = typeInfo?.Info?.DebuggerBrowsableProperties;
- if (typeFieldsBrowsableInfo == null || typeFieldsBrowsableInfo.Count == 0)
- return (fields, new List<FieldTypeClass>());
-
- var collapsedFields = new List<FieldTypeClass>();
- var rootHiddenFields = new List<FieldTypeClass>();
- foreach (var field in fields)
- {
- if (!typeFieldsBrowsableInfo.TryGetValue(field.Name, out DebuggerBrowsableState? state))
- {
- if (!typeProperitesBrowsableInfo.TryGetValue(field.Name, out DebuggerBrowsableState? propState))
- {
- collapsedFields.Add(field);
- continue;
- }
- state = propState;
- }
- switch (state)
- {
- case DebuggerBrowsableState.Never:
- break;
- case DebuggerBrowsableState.RootHidden:
- var typeName = await GetTypeName(field.TypeId, token);
- if (typeName.StartsWith("System.Collections.Generic", StringComparison.Ordinal) ||
- typeName.EndsWith("[]", StringComparison.Ordinal))
- rootHiddenFields.Add(field);
- break;
- case DebuggerBrowsableState.Collapsed:
- collapsedFields.Add(field);
- break;
- default:
- throw new NotImplementedException($"DebuggerBrowsableState: {state}");
- }
- }
- return (collapsedFields, rootHiddenFields);
- }
- async Task<JArray> GetProperties(JArray props, List<FieldTypeClass> fields, int typeId, CancellationToken token)
- {
- var typeInfo = await GetTypeInfo(typeId, token);
- var typeProperitesBrowsableInfo = typeInfo?.Info?.DebuggerBrowsableProperties;
- var regularProps = new JArray();
- foreach (var p in props)
- {
- var propName = p["name"].Value<string>();
- // if property has a backing field - avoid adding a duplicate
- if (fields.Any(field => field.Name == propName))
- continue;
- if (!typeProperitesBrowsableInfo.TryGetValue(propName, out DebuggerBrowsableState? state))
- {
- regularProps.Add(p);
- continue;
- }
- switch (state)
- {
- case DebuggerBrowsableState.Never:
- break;
- case DebuggerBrowsableState.RootHidden:
- DotnetObjectId rootObjId;
- DotnetObjectId.TryParse(p["get"]["objectId"].Value<string>(), out rootObjId);
- var rootObject = await InvokeMethodInObject(rootObjId, rootObjId.SubValue, propName, token);
- await AppendRootHiddenChildren(rootObject, regularProps);
- break;
- case DebuggerBrowsableState.Collapsed:
- regularProps.Add(p);
- break;
- default:
- throw new NotImplementedException($"DebuggerBrowsableState: {state}");
- }
- }
- return regularProps;
- }
+ public async Task<JObject> GetMethodProxy(JObject objectId, CancellationToken token)
+ {
+ var containerId = objectId["containerId"].Value<int>();
+ var methodId = objectId["methodId"].Value<int>();
+ var isValueType = objectId["isValueType"].Value<bool>();
+ return await InvokeMethod(containerId, methodId, isValueType, token);
}
public async Task<JArray> GetObjectProxy(int objectId, CancellationToken token)
{
- var ret = await GetObjectValues(objectId, GetObjectCommandOptions.WithSetter, token);
- var typeIds = await GetTypeIdFromObject(objectId, true, token);
+ GetMembersResult members = await MemberObjectsExplorer.GetObjectMemberValues(this, objectId, GetObjectCommandOptions.WithSetter, token);
+ JArray ret = members.Flatten();
+ var typeIds = await GetTypeIdsForObject(objectId, true, token);
foreach (var typeId in typeIds)
{
var retDebuggerCmdReader = await GetTypePropertiesReader(typeId, token);
arr.Add(item);
}
- public static void TryAddRange(this Dictionary<string, JToken> dict, JArray addedArr)
- {
- foreach (var item in addedArr)
- {
- var key = item["name"]?.Value<string>();
- if (key == null)
- continue;
- dict.TryAdd(key, item);
- }
- }
-
- public static JArray GetValuesByKeys(this Dictionary<string, JToken> dict, List<string> keys)
- {
- var result = new JArray();
- foreach (var name in keys)
- {
- if (!dict.TryGetValue(name, out var obj))
- continue;
- result.Add(obj);
- }
- return result;
- }
-
public static bool IsNullValuedObject(this JObject obj)
=> obj != null && obj["type"]?.Value<string>() == "object" && obj["subtype"]?.Value<string>() == "null";
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.WebAssembly.Diagnostics;
+using Newtonsoft.Json.Linq;
+
+namespace BrowserDebugProxy
+{
+ internal sealed class ValueTypeClass
+ {
+ private readonly bool autoExpand;
+ private JArray proxy;
+ private GetMembersResult _combinedResult;
+ private bool propertiesExpanded;
+ private bool fieldsExpanded;
+ private string className;
+ private JArray fields;
+
+ public DotnetObjectId Id { get; init; }
+ public byte[] Buffer { get; init; }
+ public int TypeId { get; init; }
+ public bool IsEnum { get; init; }
+
+ public ValueTypeClass(byte[] buffer, string className, JArray fields, int typeId, bool isEnum)
+ {
+ var valueTypeId = MonoSDBHelper.GetNewObjectId();
+ var objectId = new DotnetObjectId("valuetype", valueTypeId);
+
+ Buffer = buffer;
+ this.fields = fields;
+ this.className = className;
+ TypeId = typeId;
+ autoExpand = ShouldAutoExpand(className);
+ Id = objectId;
+ IsEnum = isEnum;
+ }
+
+ public override string ToString() => $"{{ ValueTypeClass: typeId: {TypeId}, Id: {Id}, Id: {Id}, fields: {fields} }}";
+
+ public static async Task<ValueTypeClass> CreateFromReader(
+ MonoSDBHelper sdbAgent,
+ MonoBinaryReader cmdReader,
+ long initialPos,
+ string className,
+ int typeId,
+ int numValues,
+ bool isEnum,
+ CancellationToken token)
+ {
+ var typeInfo = await sdbAgent.GetTypeInfo(typeId, token);
+ var typeFieldsBrowsableInfo = typeInfo?.Info?.DebuggerBrowsableFields;
+ var typePropertiesBrowsableInfo = typeInfo?.Info?.DebuggerBrowsableProperties;
+
+ IReadOnlyList<FieldTypeClass> fieldTypes = await sdbAgent.GetTypeFields(typeId, token);
+ // statics should not be in valueType fields: CallFunctionOnTests.PropertyGettersTest
+ IEnumerable<FieldTypeClass> writableFields = fieldTypes
+ .Where(f => !f.Attributes.HasFlag(FieldAttributes.Literal)
+ && !f.Attributes.HasFlag(FieldAttributes.Static));
+
+ JArray fields = new();
+ foreach (var field in writableFields)
+ {
+ var fieldValue = await sdbAgent.CreateJObjectForVariableValue(cmdReader, field.Name, token, true, field.TypeId, false);
+
+ fieldValue["__section"] = field.Attributes switch
+ {
+ FieldAttributes.Private => "private",
+ FieldAttributes.Public => "result",
+ _ => "internal"
+ };
+
+ if (field.IsBackingField)
+ fieldValue["__isBackingField"] = true;
+ else
+ {
+ typeFieldsBrowsableInfo.TryGetValue(field.Name, out DebuggerBrowsableState? state);
+ fieldValue["__state"] = state?.ToString();
+ }
+
+ fields.Add(fieldValue);
+ }
+
+ long endPos = cmdReader.BaseStream.Position;
+ cmdReader.BaseStream.Position = initialPos;
+ byte[] valueTypeBuffer = new byte[endPos - initialPos];
+ cmdReader.Read(valueTypeBuffer, 0, (int)(endPos - initialPos));
+ cmdReader.BaseStream.Position = endPos;
+
+ return new ValueTypeClass(valueTypeBuffer, className, fields, typeId, isEnum);
+ }
+
+ public async Task<JObject> ToJObject(MonoSDBHelper sdbAgent, bool forDebuggerDisplayAttribute, CancellationToken token)
+ {
+ string description = className;
+ if (ShouldAutoInvokeToString(className) || IsEnum)
+ {
+ int methodId = await sdbAgent.GetMethodIdByName(TypeId, "ToString", token);
+ var retMethod = await sdbAgent.InvokeMethod(Buffer, methodId, token, "methodRet");
+ description = retMethod["value"]?["value"].Value<string>();
+ if (className.Equals("System.Guid"))
+ description = description.ToUpperInvariant(); //to keep the old behavior
+ }
+ else if (!forDebuggerDisplayAttribute)
+ {
+ string displayString = await sdbAgent.GetValueFromDebuggerDisplayAttribute(Id, TypeId, token);
+ if (displayString != null)
+ description = displayString;
+ }
+
+ var obj = MonoSDBHelper.CreateJObject<string>(null, "object", description, false, className, Id.ToString(), null, null, true, true, IsEnum);
+ return obj;
+ }
+
+ public async Task<JArray> GetProxy(MonoSDBHelper sdbHelper, CancellationToken token)
+ {
+ if (proxy != null)
+ return proxy;
+
+ var retDebuggerCmdReader = await sdbHelper.GetTypePropertiesReader(TypeId, token);
+ if (retDebuggerCmdReader == null)
+ return null;
+
+ if (!fieldsExpanded)
+ {
+ await ExpandedFieldValues(sdbHelper, includeStatic: false, token);
+ fieldsExpanded = true;
+ }
+ proxy = new JArray(fields);
+
+ var nProperties = retDebuggerCmdReader.ReadInt32();
+
+ for (int i = 0; i < nProperties; i++)
+ {
+ retDebuggerCmdReader.ReadInt32(); //propertyId
+ string propertyNameStr = retDebuggerCmdReader.ReadString();
+
+ var getMethodId = retDebuggerCmdReader.ReadInt32();
+ retDebuggerCmdReader.ReadInt32(); //setmethod
+ retDebuggerCmdReader.ReadInt32(); //attrs
+ if (await sdbHelper.MethodIsStatic(getMethodId, token))
+ continue;
+ using var command_params_writer_to_proxy = new MonoBinaryWriter();
+ command_params_writer_to_proxy.Write(getMethodId);
+ command_params_writer_to_proxy.Write(Buffer);
+ command_params_writer_to_proxy.Write(0);
+
+ var (data, length) = command_params_writer_to_proxy.ToBase64();
+ proxy.Add(JObject.FromObject(new
+ {
+ get = JObject.FromObject(new
+ {
+ commandSet = CommandSet.Vm,
+ command = CmdVM.InvokeMethod,
+ buffer = data,
+ length = length,
+ id = MonoSDBHelper.GetNewId()
+ }),
+ name = propertyNameStr
+ }));
+ }
+ return proxy;
+ }
+
+ public async Task<GetMembersResult> GetMemberValues(
+ MonoSDBHelper sdbHelper, GetObjectCommandOptions getObjectOptions, bool sortByAccessLevel, bool includeStatic, CancellationToken token)
+ {
+ // 1
+ if (!propertiesExpanded)
+ {
+ await ExpandPropertyValues(sdbHelper, sortByAccessLevel, includeStatic, token);
+ propertiesExpanded = true;
+ }
+
+ // 2
+ GetMembersResult result = null;
+ if (!getObjectOptions.HasFlag(GetObjectCommandOptions.ForDebuggerDisplayAttribute))
+ {
+ // FIXME: cache?
+ result = await sdbHelper.GetValuesFromDebuggerProxyAttribute(Id.Value, TypeId, token);
+ if (result != null)
+ Console.WriteLine($"Investigate GetValuesFromDebuggerProxyAttribute\n{result}. There was a change of logic from loop to one iteration");
+ }
+
+ if (result == null && getObjectOptions.HasFlag(GetObjectCommandOptions.AccessorPropertiesOnly))
+ {
+ // 3 - just properties, skip fields
+ result = _combinedResult.Clone();
+ RemovePropertiesFrom(result.Result);
+ RemovePropertiesFrom(result.PrivateMembers);
+ RemovePropertiesFrom(result.OtherMembers);
+ }
+
+ if (result == null)
+ {
+ // 4 - fields + properties
+ result = _combinedResult.Clone();
+ }
+
+ return result;
+
+ static void RemovePropertiesFrom(JArray collection)
+ {
+ List<JToken> toRemove = new();
+ foreach (JToken jt in collection)
+ {
+ if (jt is not JObject obj || obj["get"] != null)
+ continue;
+ toRemove.Add(jt);
+ }
+ foreach (var jt in toRemove)
+ {
+ collection.Remove(jt);
+ }
+ }
+ }
+
+ public async Task ExpandedFieldValues(MonoSDBHelper sdbHelper, bool includeStatic, CancellationToken token)
+ {
+ JArray visibleFields = new();
+ foreach (JObject field in fields)
+ {
+ if (!Enum.TryParse(field["__state"]?.Value<string>(), out DebuggerBrowsableState state))
+ {
+ visibleFields.Add(field);
+ continue;
+ }
+ var fieldValue = field["value"] ?? field["get"];
+ string typeName = fieldValue?["className"]?.Value<string>();
+ JArray fieldMembers = await MemberObjectsExplorer.GetExpandedMemberValues(
+ sdbHelper, typeName, field["name"]?.Value<string>(), field, state, includeStatic, token);
+ visibleFields.AddRange(fieldMembers);
+ }
+ fields = visibleFields;
+ }
+
+ public async Task ExpandPropertyValues(MonoSDBHelper sdbHelper, bool splitMembersByAccessLevel, bool includeStatic, CancellationToken token)
+ {
+ using var commandParamsWriter = new MonoBinaryWriter();
+ commandParamsWriter.Write(TypeId);
+ using MonoBinaryReader getParentsReader = await sdbHelper.SendDebuggerAgentCommand(CmdType.GetParents, commandParamsWriter, token);
+ int numParents = getParentsReader.ReadInt32();
+
+ if (!fieldsExpanded)
+ {
+ await ExpandedFieldValues(sdbHelper, includeStatic, token);
+ fieldsExpanded = true;
+ }
+
+ var allMembers = new Dictionary<string, JObject>();
+ foreach (var f in fields)
+ allMembers[f["name"].Value<string>()] = f as JObject;
+
+ int typeId = TypeId;
+ var parentsCntPlusSelf = numParents + 1;
+ for (int i = 0; i < parentsCntPlusSelf; i++)
+ {
+ // isParent:
+ if (i != 0) typeId = getParentsReader.ReadInt32();
+
+ allMembers = await MemberObjectsExplorer.GetNonAutomaticPropertyValues(
+ sdbHelper,
+ typeId,
+ className,
+ Buffer,
+ autoExpand,
+ Id,
+ isValueType: true,
+ isOwn: i == 0,
+ token,
+ allMembers,
+ includeStatic);
+ }
+ _combinedResult = GetMembersResult.FromValues(allMembers.Values, splitMembersByAccessLevel);
+ }
+
+ private static bool ShouldAutoExpand(string className)
+ => className is "System.DateTime" or
+ "System.DateTimeOffset" or
+ "System.TimeSpan";
+
+ private static bool ShouldAutoInvokeToString(string className)
+ => className is "System.DateTime" or
+ "System.DateTimeOffset" or
+ "System.TimeSpan" or
+ "System.Decimal" or
+ "System.Guid";
+ }
+}
Assert.Equal(value, val);
}
+ internal void CheckContainsJObject(JToken locals, JToken comparedTo, string name)
+ {
+ var val = GetAndAssertObjectWithName(locals, name);
+ JObject refValue = (JObject)val["value"];
+ refValue?.Property("objectId")?.Remove();
+ JObject comparedToValue = (JObject)comparedTo["value"];
+ comparedToValue?.Property("objectId")?.Remove();
+ Assert.Equal(val, comparedTo);
+ }
+
internal async Task<JToken> CheckValueType(JToken locals, string name, string class_name, string description=null)
{
var l = GetAndAssertObjectWithName(locals, name);
Assert.True(actual_obj != null, $"[{label}] not value found for property named '{exp_name}'");
- var actual_val = actual_obj["value"];
if (exp_val.Type == JTokenType.Array)
{
- var actual_props = await GetProperties(actual_val["objectId"]?.Value<string>());
+ var actual_props = await GetProperties(actual_obj["value"]["objectId"]?.Value<string>());
await CheckProps(actual_props, exp_val, $"{label}-{exp_name}");
}
else if (exp_val["__custom_type"] != null && exp_val["__custom_type"]?.Value<string>() == "getter")
{
// hack: for getters, actual won't have a .value
+ // are we doing it on purpose? Why? CHECK if properties are displayed in Browser/VS, if not revert the value field here
+ // we should be leaving properties, not their backing fields
await CheckCustomType(actual_obj, exp_val, $"{label}#{exp_name}");
}
else
{
- await CheckValue(actual_val, exp_val, $"{label}#{exp_name}");
+ await CheckValue(actual_obj["value"], exp_val, $"{label}#{exp_name}");
}
}
}
"window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })",
wait_for_event_fn: async (pause_location) =>
{
- var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
+ var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
- var (_, res) = await EvaluateOnCallFrame(id, "this.objToTest.MyMethodWrong()", expect_ok: false );
- Assert.Contains($"Method 'MyMethodWrong' not found", res.Error["message"]?.Value<string>());
+ var (_, res) = await EvaluateOnCallFrame(id, "this.objToTest.MyMethodWrong()", expect_ok: false );
+ Assert.Contains($"Method 'MyMethodWrong' not found", res.Error["message"]?.Value<string>());
- (_, res) = await EvaluateOnCallFrame(id, "this.objToTest.MyMethod(1)", expect_ok: false);
- Assert.Contains("Cannot invoke method 'this.objToTest.MyMethod(1)' - too many arguments passed", res.Error["message"]?.Value<string>());
+ (_, res) = await EvaluateOnCallFrame(id, "this.objToTest.MyMethod(1)", expect_ok: false);
+ Assert.Contains("Cannot invoke method 'this.objToTest.MyMethod(1)' - too many arguments passed", res.Error["message"]?.Value<string>());
- (_, res) = await EvaluateOnCallFrame(id, "this.CallMethodWithParm(\"1\")", expect_ok: false );
- Assert.Contains("Unable to evaluate method 'this.CallMethodWithParm(\"1\")'", res.Error["message"]?.Value<string>());
+ (_, res) = await EvaluateOnCallFrame(id, "this.CallMethodWithParm(\"1\")", expect_ok: false );
+ Assert.Contains("Unable to evaluate method 'this.CallMethodWithParm(\"1\")'", res.Error["message"]?.Value<string>());
- (_, res) = await EvaluateOnCallFrame(id, "this.ParmToTestObjNull.MyMethod()", expect_ok: false );
- Assert.Contains("Expression 'this.ParmToTestObjNull.MyMethod' evaluated to null", res.Error["message"]?.Value<string>());
+ (_, res) = await EvaluateOnCallFrame(id, "this.ParmToTestObjNull.MyMethod()", expect_ok: false );
+ Assert.Contains("Expression 'this.ParmToTestObjNull.MyMethod' evaluated to null", res.Error["message"]?.Value<string>());
- (_, res) = await EvaluateOnCallFrame(id, "this.ParmToTestObjException.MyMethod()", expect_ok: false );
- Assert.Contains("Cannot invoke method 'MyMethod'", res.Error["message"]?.Value<string>());
+ (_, res) = await EvaluateOnCallFrame(id, "this.ParmToTestObjException.MyMethod()", expect_ok: false );
+ Assert.Contains("Cannot invoke method 'MyMethod'", res.Error["message"]?.Value<string>());
});
[Fact]
"window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })",
wait_for_event_fn: async (pause_location) =>
{
- var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
+ var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
- var frame = pause_location["callFrames"][0];
- var props = await GetObjectOnFrame(frame, "this");
- CheckNumber(props, "a", 1);
+ var frame = pause_location["callFrames"][0];
+ var props = await GetObjectOnFrame(frame, "this");
+ CheckNumber(props, "a", 1);
- await EvaluateOnCallFrameAndCheck(id,
- ("this.CallMethodChangeValue()", TObject("object", is_null : true)));
+ await EvaluateOnCallFrameAndCheck(id,
+ ("this.CallMethodChangeValue()", TObject("object", is_null : true)));
- frame = pause_location["callFrames"][0];
- props = await GetObjectOnFrame(frame, "this");
- CheckNumber(props, "a", 11);
+ frame = pause_location["callFrames"][0];
+ props = await GetObjectOnFrame(frame, "this");
+ CheckNumber(props, "a", 11);
});
[Fact]
"window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })",
wait_for_event_fn: async (pause_location) =>
{
- var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
+ var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
- var frame = pause_location["callFrames"][0];
+ var frame = pause_location["callFrames"][0];
- await EvaluateOnCallFrameAndCheck(id,
- ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10)));
- await EvaluateOnCallFrameAndCheck(id,
- ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")));
- await EvaluateOnCallFrameAndCheck(id,
- ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")));
+ await EvaluateOnCallFrameAndCheck(id,
+ ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10)));
+ await EvaluateOnCallFrameAndCheck(id,
+ ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")));
+ await EvaluateOnCallFrameAndCheck(id,
+ ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")));
});
[Theory]
$"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] {type}:{method}'); }})",
wait_for_event_fn: async (pause_location) =>
{
- var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
+ var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
- var frame = pause_location["callFrames"][0];
+ var frame = pause_location["callFrames"][0];
- await EvaluateOnCallFrameAndCheck(id,
- ("EvaluateStaticClass.StaticField1", TNumber(10)),
- ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")),
- ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")),
- ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10)),
- ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")),
- ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")));
+ await EvaluateOnCallFrameAndCheck(id,
+ ("EvaluateStaticClass.StaticField1", TNumber(10)),
+ ("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")),
+ ("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")),
+ ("DebuggerTests.EvaluateStaticClass.StaticField1", TNumber(10)),
+ ("DebuggerTests.EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")),
+ ("DebuggerTests.EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")));
});
[Fact]
"window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateAsyncMethods'); })",
wait_for_event_fn: async (pause_location) =>
{
- var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
+ var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
- var frame = pause_location["callFrames"][0];
+ var frame = pause_location["callFrames"][0];
- await EvaluateOnCallFrameAndCheck(id,
- ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10)),
- ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1")),
- ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented")),
- ("EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10)),
- ("EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1")),
- ("EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented")));
+ await EvaluateOnCallFrameAndCheck(id,
+ ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10)),
+ ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1")),
+ ("DebuggerTests.EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented")),
+ ("EvaluateNonStaticClassWithStaticFields.StaticField1", TNumber(10)),
+ ("EvaluateNonStaticClassWithStaticFields.StaticProperty1", TString("StaticProperty1")),
+ ("EvaluateNonStaticClassWithStaticFields.StaticPropertyWithError", TString("System.Exception: not implemented")));
});
- [Fact]
+ [ConditionalFact(nameof(RunningOnChrome))]
public async Task EvaluateStaticClassesNested() => await CheckInspectLocalsAtBreakpointSite(
"DebuggerTests.EvaluateMethodTestsClass", "EvaluateMethods", 3, "EvaluateMethods",
"window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })",
wait_for_event_fn: async (pause_location) =>
{
- var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
+ var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
- var frame = pause_location["callFrames"][0];
+ var frame = pause_location["callFrames"][0];
- await EvaluateOnCallFrameAndCheck(id,
- ("DebuggerTests.EvaluateStaticClass.NestedClass1.NestedClass2.NestedClass3.StaticField1", TNumber(3)),
- ("DebuggerTests.EvaluateStaticClass.NestedClass1.NestedClass2.NestedClass3.StaticProperty1", TString("StaticProperty3")),
- ("DebuggerTests.EvaluateStaticClass.NestedClass1.NestedClass2.NestedClass3.StaticPropertyWithError", TString("System.Exception: not implemented 3")),
- ("EvaluateStaticClass.NestedClass1.NestedClass2.NestedClass3.StaticField1", TNumber(3)),
- ("EvaluateStaticClass.NestedClass1.NestedClass2.NestedClass3.StaticProperty1", TString("StaticProperty3")),
- ("EvaluateStaticClass.NestedClass1.NestedClass2.NestedClass3.StaticPropertyWithError", TString("System.Exception: not implemented 3")));
+ await EvaluateOnCallFrameAndCheck(id,
+ ("DebuggerTests.EvaluateStaticClass.NestedClass1.NestedClass2.NestedClass3.StaticField1", TNumber(3)),
+ ("DebuggerTests.EvaluateStaticClass.NestedClass1.NestedClass2.NestedClass3.StaticProperty1", TString("StaticProperty3")),
+ ("DebuggerTests.EvaluateStaticClass.NestedClass1.NestedClass2.NestedClass3.StaticPropertyWithError", TString("System.Exception: not implemented 3")),
+ ("EvaluateStaticClass.NestedClass1.NestedClass2.NestedClass3.StaticField1", TNumber(3)),
+ ("EvaluateStaticClass.NestedClass1.NestedClass2.NestedClass3.StaticProperty1", TString("StaticProperty3")),
+ ("EvaluateStaticClass.NestedClass1.NestedClass2.NestedClass3.StaticPropertyWithError", TString("System.Exception: not implemented 3")));
});
[Fact]
"window.setTimeout(function() { invoke_static_method ('[debugger-test] NoNamespaceClass:EvaluateMethods'); })",
wait_for_event_fn: async (pause_location) =>
{
- var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
+ var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
- var frame = pause_location["callFrames"][0];
+ var frame = pause_location["callFrames"][0];
- await EvaluateOnCallFrameAndCheck(id,
- ("NoNamespaceClass.NestedClass1.NestedClass2.NestedClass3.StaticField1", TNumber(30)),
- ("NoNamespaceClass.NestedClass1.NestedClass2.NestedClass3.StaticProperty1", TString("StaticProperty30")),
- ("NoNamespaceClass.NestedClass1.NestedClass2.NestedClass3.StaticPropertyWithError", TString("System.Exception: not implemented 30")));
+ await EvaluateOnCallFrameAndCheck(id,
+ ("NoNamespaceClass.NestedClass1.NestedClass2.NestedClass3.StaticField1", TNumber(30)),
+ ("NoNamespaceClass.NestedClass1.NestedClass2.NestedClass3.StaticProperty1", TString("StaticProperty30")),
+ ("NoNamespaceClass.NestedClass1.NestedClass2.NestedClass3.StaticPropertyWithError", TString("System.Exception: not implemented 30")));
});
[ConditionalFact(nameof(RunningOnChrome))]
("EvaluateStaticClass.StaticField1", TNumber(10)),
("EvaluateStaticClass.StaticProperty1", TString("StaticProperty1")),
("EvaluateStaticClass.StaticPropertyWithError", TString("System.Exception: not implemented")));
- });
+ });
[ConditionalFact(nameof(RunningOnChrome))]
public async Task EvaluateStaticClassInvalidField() => await CheckInspectLocalsAtBreakpointSite(
"window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.EvaluateMethodTestsClass:EvaluateMethods'); })",
wait_for_event_fn: async (pause_location) =>
{
- var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
+ var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
- var frame = pause_location["callFrames"][0];
+ var frame = pause_location["callFrames"][0];
- var (_, res) = await EvaluateOnCallFrame(id, "DebuggerTests.EvaluateStaticClass.StaticProperty2", expect_ok: false);
- AssertEqual("Failed to resolve member access for DebuggerTests.EvaluateStaticClass.StaticProperty2", res.Error["result"]?["description"]?.Value<string>(), "wrong error message");
+ var (_, res) = await EvaluateOnCallFrame(id, "DebuggerTests.EvaluateStaticClass.StaticProperty2", expect_ok: false);
+ AssertEqual("Failed to resolve member access for DebuggerTests.EvaluateStaticClass.StaticProperty2", res.Error["result"]?["description"]?.Value<string>(), "wrong error message");
- (_, res) = await EvaluateOnCallFrame(id, "DebuggerTests.InvalidEvaluateStaticClass.StaticProperty2", expect_ok: false);
- AssertEqual("Failed to resolve member access for DebuggerTests.InvalidEvaluateStaticClass.StaticProperty2", res.Error["result"]?["description"]?.Value<string>(), "wrong error message");
+ (_, res) = await EvaluateOnCallFrame(id, "DebuggerTests.InvalidEvaluateStaticClass.StaticProperty2", expect_ok: false);
+ AssertEqual("Failed to resolve member access for DebuggerTests.InvalidEvaluateStaticClass.StaticProperty2", res.Error["result"]?["description"]?.Value<string>(), "wrong error message");
});
- [ConditionalFact(nameof(RunningOnChrome))]
- public async Task AsyncLocalsInContinueWithBlock() => await CheckInspectLocalsAtBreakpointSite(
- "DebuggerTests.AsyncTests.ContinueWithTests", "ContinueWithStaticAsync", 4, "<ContinueWithStaticAsync>b__3_0",
- "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerTests.AsyncTests.ContinueWithTests:RunAsync'); })",
- wait_for_event_fn: async (pause_location) =>
- {
- var frame_locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value<string>());
- var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
+ [ConditionalFact(nameof(RunningOnChrome))]
+ public async Task AsyncLocalsInContinueWithBlock() => await CheckInspectLocalsAtBreakpointSite(
+ "DebuggerTests.AsyncTests.ContinueWithTests", "ContinueWithStaticAsync", 4, "<ContinueWithStaticAsync>b__3_0",
+ "window.setTimeout(function() { invoke_static_method('[debugger-test] DebuggerTests.AsyncTests.ContinueWithTests:RunAsync'); })",
+ wait_for_event_fn: async (pause_location) =>
+ {
+ var frame_locals = await GetProperties(pause_location["callFrames"][0]["callFrameId"].Value<string>());
+ var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
- await EvaluateOnCallFrameAndCheck(id,
- ($"t.Status", TEnum("System.Threading.Tasks.TaskStatus", "RanToCompletion")),
- ($" t.Status", TEnum("System.Threading.Tasks.TaskStatus", "RanToCompletion"))
- );
-
- await EvaluateOnCallFrameFail(id,
- ("str", "ReferenceError"),
- (" str", "ReferenceError")
- );
- });
+ await EvaluateOnCallFrameAndCheck(id,
+ ($"t.Status", TEnum("System.Threading.Tasks.TaskStatus", "RanToCompletion")),
+ ($" t.Status", TEnum("System.Threading.Tasks.TaskStatus", "RanToCompletion"))
+ );
+
+ await EvaluateOnCallFrameFail(id,
+ ("str", "ReferenceError"),
+ (" str", "ReferenceError")
+ );
+ });
[ConditionalFact(nameof(RunningOnChrome))]
public async Task EvaluateConstantValueUsingRuntimeEvaluate() => await CheckInspectLocalsAtBreakpointSite(
});
[ConditionalTheory(nameof(RunningOnChrome))]
- [InlineData("EvaluateBrowsableProperties", "TestEvaluateFieldsNone", "testFieldsNone", 10)]
- [InlineData("EvaluateBrowsableProperties", "TestEvaluatePropertiesNone", "testPropertiesNone", 10)]
- [InlineData("EvaluateBrowsableCustomProperties", "TestEvaluatePropertiesNone", "testPropertiesNone", 5, true)]
- public async Task EvaluateBrowsableNone(string outerClassName, string className, string localVarName, int breakLine, bool isCustomGetter = false) => await CheckInspectLocalsAtBreakpointSite(
+ [InlineData("EvaluateBrowsableClass", "TestEvaluateFieldsNone", "testFieldsNone", 10)]
+ [InlineData("EvaluateBrowsableClass", "TestEvaluatePropertiesNone", "testPropertiesNone", 10)]
+ [InlineData("EvaluateBrowsableStruct", "TestEvaluateFieldsNone", "testFieldsNone", 10)]
+ [InlineData("EvaluateBrowsableStruct", "TestEvaluatePropertiesNone", "testPropertiesNone", 10)]
+ [InlineData("EvaluateBrowsableStaticClass", "TestEvaluateFieldsNone", "testFieldsNone", 10)]
+ [InlineData("EvaluateBrowsableStaticClass", "TestEvaluatePropertiesNone", "testPropertiesNone", 10)]
+ [InlineData("EvaluateBrowsableCustomPropertiesClass", "TestEvaluatePropertiesNone", "testPropertiesNone", 5, true)]
+ public async Task EvaluateBrowsableNone(
+ string outerClassName, string className, string localVarName, int breakLine, bool isCustomGetter = false) => await CheckInspectLocalsAtBreakpointSite(
$"DebuggerTests.{outerClassName}", "Evaluate", breakLine, "Evaluate",
$"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.{outerClassName}:Evaluate'); 1 }})",
wait_for_event_fn: async (pause_location) =>
{
list = TGetter("list", TObject("System.Collections.Generic.List<int>", description: "Count = 2")),
array = TGetter("array", TObject("int[]", description: "int[2]")),
- text = TGetter("text", TString("text"))
+ text = TGetter("text", TString("text")),
+ nullNone = TGetter("nullNone", TObject("bool[]", is_null: true)),
+ valueTypeEnum = TGetter("valueTypeEnum", TEnum("DebuggerTests.SampleEnum", "yes")),
+ sampleStruct = TGetter("sampleStruct", TObject("DebuggerTests.SampleStructure", description: "DebuggerTests.SampleStructure")),
+ sampleClass = TGetter("sampleClass", TObject("DebuggerTests.SampleClass", description: "DebuggerTests.SampleClass"))
}, "testNoneProps#1");
else
await CheckProps(testNoneProps, new
{
list = TObject("System.Collections.Generic.List<int>", description: "Count = 2"),
array = TObject("int[]", description: "int[2]"),
- text = TString("text")
+ text = TString("text"),
+ nullNone = TObject("bool[]", is_null: true),
+ valueTypeEnum = TEnum("DebuggerTests.SampleEnum", "yes"),
+ sampleStruct = TObject("DebuggerTests.SampleStructure", description: "DebuggerTests.SampleStructure"),
+ sampleClass = TObject("DebuggerTests.SampleClass", description: "DebuggerTests.SampleClass")
}, "testNoneProps#1");
- });
+ });
- [Theory]
- [InlineData("EvaluateBrowsableProperties", "TestEvaluateFieldsNever", "testFieldsNever", 10)]
- [InlineData("EvaluateBrowsableProperties", "TestEvaluatePropertiesNever", "testPropertiesNever", 10)]
- [InlineData("EvaluateBrowsableStaticProperties", "TestEvaluateFieldsNever", "testFieldsNever", 10)]
- [InlineData("EvaluateBrowsableStaticProperties", "TestEvaluatePropertiesNever", "testPropertiesNever", 10)]
- [InlineData("EvaluateBrowsableCustomProperties", "TestEvaluatePropertiesNever", "testPropertiesNever", 5)]
+ [ConditionalTheory(nameof(RunningOnChrome))]
+ [InlineData("EvaluateBrowsableClass", "TestEvaluateFieldsNever", "testFieldsNever", 10)]
+ [InlineData("EvaluateBrowsableClass", "TestEvaluatePropertiesNever", "testPropertiesNever", 10)]
+ [InlineData("EvaluateBrowsableStruct", "TestEvaluateFieldsNever", "testFieldsNever", 10)]
+ [InlineData("EvaluateBrowsableStruct", "TestEvaluatePropertiesNever", "testPropertiesNever", 10)]
+ [InlineData("EvaluateBrowsableStaticClass", "TestEvaluateFieldsNever", "testFieldsNever", 10)]
+ [InlineData("EvaluateBrowsableStaticClass", "TestEvaluatePropertiesNever", "testPropertiesNever", 10)]
+ [InlineData("EvaluateBrowsableCustomPropertiesClass", "TestEvaluatePropertiesNever", "testPropertiesNever", 5)]
public async Task EvaluateBrowsableNever(string outerClassName, string className, string localVarName, int breakLine) => await CheckInspectLocalsAtBreakpointSite(
$"DebuggerTests.{outerClassName}", "Evaluate", breakLine, "Evaluate",
$"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.{outerClassName}:Evaluate'); 1 }})",
await CheckProps(testNeverProps, new
{
}, "testNeverProps#1");
- });
+ });
[ConditionalTheory(nameof(RunningOnChrome))]
- [InlineData("EvaluateBrowsableProperties", "TestEvaluateFieldsCollapsed", "testFieldsCollapsed", 10)]
- [InlineData("EvaluateBrowsableProperties", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 10)]
- [InlineData("EvaluateBrowsableStaticProperties", "TestEvaluateFieldsCollapsed", "testFieldsCollapsed", 10)]
- [InlineData("EvaluateBrowsableStaticProperties", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 10)]
- [InlineData("EvaluateBrowsableCustomProperties", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 5, true)]
- public async Task EvaluateBrowsableCollapsed(string outerClassName, string className, string localVarName, int breakLine, bool isCustomGetter = false) => await CheckInspectLocalsAtBreakpointSite(
+ [InlineData("EvaluateBrowsableClass", "TestEvaluateFieldsCollapsed", "testFieldsCollapsed", 10)]
+ [InlineData("EvaluateBrowsableClass", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 10)]
+ [InlineData("EvaluateBrowsableStruct", "TestEvaluateFieldsCollapsed", "testFieldsCollapsed", 10)]
+ [InlineData("EvaluateBrowsableStruct", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 10)]
+ [InlineData("EvaluateBrowsableStaticClass", "TestEvaluateFieldsCollapsed", "testFieldsCollapsed", 10)]
+ [InlineData("EvaluateBrowsableStaticClass", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 10)]
+ [InlineData("EvaluateBrowsableCustomPropertiesClass", "TestEvaluatePropertiesCollapsed", "testPropertiesCollapsed", 5, true)]
+ public async Task EvaluateBrowsableCollapsed(
+ string outerClassName, string className, string localVarName, int breakLine, bool isCustomGetter = false) => await CheckInspectLocalsAtBreakpointSite(
$"DebuggerTests.{outerClassName}", "Evaluate", breakLine, "Evaluate",
$"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.{outerClassName}:Evaluate'); 1 }})",
wait_for_event_fn: async (pause_location) =>
{
listCollapsed = TGetter("listCollapsed", TObject("System.Collections.Generic.List<int>", description: "Count = 2")),
arrayCollapsed = TGetter("arrayCollapsed", TObject("int[]", description: "int[2]")),
- textCollapsed = TGetter("textCollapsed", TString("textCollapsed"))
+ textCollapsed = TGetter("textCollapsed", TString("textCollapsed")),
+ nullCollapsed = TGetter("nullCollapsed", TObject("bool[]", is_null: true)),
+ valueTypeEnumCollapsed = TGetter("valueTypeEnumCollapsed", TEnum("DebuggerTests.SampleEnum", "yes")),
+ sampleStructCollapsed = TGetter("sampleStructCollapsed", TObject("DebuggerTests.SampleStructure", description: "DebuggerTests.SampleStructure")),
+ sampleClassCollapsed = TGetter("sampleClassCollapsed", TObject("DebuggerTests.SampleClass", description: "DebuggerTests.SampleClass"))
}, "testCollapsedProps#1");
else
await CheckProps(testCollapsedProps, new
{
listCollapsed = TObject("System.Collections.Generic.List<int>", description: "Count = 2"),
arrayCollapsed = TObject("int[]", description: "int[2]"),
- textCollapsed = TString("textCollapsed")
+ textCollapsed = TString("textCollapsed"),
+ nullCollapsed = TObject("bool[]", is_null: true),
+ valueTypeEnumCollapsed = TEnum("DebuggerTests.SampleEnum", "yes"),
+ sampleStructCollapsed = TObject("DebuggerTests.SampleStructure", description: "DebuggerTests.SampleStructure"),
+ sampleClassCollapsed = TObject("DebuggerTests.SampleClass", description: "DebuggerTests.SampleClass")
}, "testCollapsedProps#1");
- });
+ });
- [Theory]
- [InlineData("EvaluateBrowsableProperties", "TestEvaluateFieldsRootHidden", "testFieldsRootHidden", 10)]
- [InlineData("EvaluateBrowsableProperties", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 10)]
- [InlineData("EvaluateBrowsableStaticProperties", "TestEvaluateFieldsRootHidden", "testFieldsRootHidden", 10)]
- [InlineData("EvaluateBrowsableStaticProperties", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 10)]
- [InlineData("EvaluateBrowsableCustomProperties", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 5, true)]
- public async Task EvaluateBrowsableRootHidden(string outerClassName, string className, string localVarName, int breakLine, bool isCustomGetter = false) => await CheckInspectLocalsAtBreakpointSite(
+ [ConditionalTheory(nameof(RunningOnChrome))]
+ [InlineData("EvaluateBrowsableClass", "TestEvaluateFieldsRootHidden", "testFieldsRootHidden", 10)]
+ [InlineData("EvaluateBrowsableClass", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 10)]
+ [InlineData("EvaluateBrowsableStruct", "TestEvaluateFieldsRootHidden", "testFieldsRootHidden", 10)]
+ [InlineData("EvaluateBrowsableStruct", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 10)]
+ [InlineData("EvaluateBrowsableStaticClass", "TestEvaluateFieldsRootHidden", "testFieldsRootHidden", 10)]
+ [InlineData("EvaluateBrowsableStaticClass", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 10)]
+ [InlineData("EvaluateBrowsableCustomPropertiesClass", "TestEvaluatePropertiesRootHidden", "testPropertiesRootHidden", 5)]
+ public async Task EvaluateBrowsableRootHidden(
+ string outerClassName, string className, string localVarName, int breakLine) => await CheckInspectLocalsAtBreakpointSite(
$"DebuggerTests.{outerClassName}", "Evaluate", breakLine, "Evaluate",
$"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.{outerClassName}:Evaluate'); 1 }})",
wait_for_event_fn: async (pause_location) =>
var (testRootHidden, _) = await EvaluateOnCallFrame(id, localVarName);
await CheckValue(testRootHidden, TObject($"DebuggerTests.{outerClassName}.{className}"), nameof(testRootHidden));
var testRootHiddenProps = await GetProperties(testRootHidden["objectId"]?.Value<string>());
+
var (refList, _) = await EvaluateOnCallFrame(id, "testPropertiesNone.list");
var refListProp = await GetProperties(refList["objectId"]?.Value<string>());
- var refListElementsProp = await GetProperties(refListProp[0]["value"]["objectId"]?.Value<string>());
+ var list = refListProp
+ .Where(v => v["name"]?.Value<string>() == "Items" || v["name"]?.Value<string>() == "_items")
+ .FirstOrDefault();
+ var refListElementsProp = await GetProperties(list["value"]["objectId"]?.Value<string>());
+
var (refArray, _) = await EvaluateOnCallFrame(id, "testPropertiesNone.array");
var refArrayProp = await GetProperties(refArray["objectId"]?.Value<string>());
+ var (refStruct, _) = await EvaluateOnCallFrame(id, "testPropertiesNone.sampleStruct");
+ var refStructProp = await GetProperties(refStruct["objectId"]?.Value<string>());
+
+ var (refClass, _) = await EvaluateOnCallFrame(id, "testPropertiesNone.sampleClass");
+ var refClassProp = await GetProperties(refClass["objectId"]?.Value<string>());
+
+ int refItemsCnt = refListElementsProp.Count() + refArrayProp.Count() + refStructProp.Count() + refClassProp.Count();
+ Assert.Equal(refItemsCnt, testRootHiddenProps.Count());
+
//in Console App names are in []
//adding variable name to make elements unique
+ foreach (var item in refListElementsProp)
+ {
+ item["name"] = string.Concat("listRootHidden[", item["name"], "]");
+ CheckContainsJObject(testRootHiddenProps, item, item["name"].Value<string>());
+ }
foreach (var item in refArrayProp)
{
item["name"] = string.Concat("arrayRootHidden[", item["name"], "]");
+ CheckContainsJObject(testRootHiddenProps, item, item["name"].Value<string>());
}
- foreach (var item in refListElementsProp)
+
+ // valuetype/class members unique names are created by concatenation with a dot
+ foreach (var item in refStructProp)
{
- item["name"] = string.Concat("listRootHidden[", item["name"], "]");
+ item["name"] = string.Concat("sampleStructRootHidden.", item["name"]);
+ CheckContainsJObject(testRootHiddenProps, item, item["name"].Value<string>());
}
- var mergedRefItems = new JArray(refListElementsProp.Union(refArrayProp));
- Assert.Equal(mergedRefItems, testRootHiddenProps);
- });
+ foreach (var item in refClassProp)
+ {
+ item["name"] = string.Concat("sampleClassRootHidden.", item["name"]);
+ CheckContainsJObject(testRootHiddenProps, item, item["name"].Value<string>());
+ }
+ });
[ConditionalFact(nameof(RunningOnChrome))]
public async Task EvaluateStaticAttributeInAssemblyNotRelatedButLoaded() => await CheckInspectLocalsAtBreakpointSite(
});
[ConditionalFact(nameof(RunningOnChrome))]
- public async Task EvaluateProtectionLevels() => await CheckInspectLocalsAtBreakpointSite(
- "DebuggerTests.GetPropertiesTests.DerivedClass", "InstanceMethod", 1, "InstanceMethod",
- "window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.GetPropertiesTests.DerivedClass:run'); })",
- wait_for_event_fn: async (pause_location) =>
- {
- var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
- var (obj, _) = await EvaluateOnCallFrame(id, "this");
- var (pub, internalAndProtected, priv) = await GetPropertiesSortedByProtectionLevels(obj["objectId"]?.Value<string>());
-
- await CheckProps(pub, new
- {
- a = TNumber(4),
- Base_AutoStringPropertyForOverrideWithField = TString("DerivedClass#Base_AutoStringPropertyForOverrideWithField"),
- Base_GetterForOverrideWithField = TString("DerivedClass#Base_GetterForOverrideWithField"),
- BaseBase_MemberForOverride = TString("DerivedClass#BaseBase_MemberForOverride"),
- DateTime = TGetter("DateTime", TDateTime(new DateTime(2200, 5, 6, 7, 18, 9))),
- _DTProp = TGetter("_DTProp", TDateTime(new DateTime(2200, 5, 6, 7, 8, 9))),
- FirstName = TGetter("FirstName", TString("DerivedClass#FirstName")),
- _base_dateTime = TGetter("_base_dateTime", TDateTime(new DateTime(2134, 5, 7, 1, 9, 2))),
- LastName = TGetter("LastName", TString("BaseClass#LastName"))
- }, "public");
-
- await CheckProps(internalAndProtected, new
- {
- base_num = TNumber(5)
- }, "internalAndProtected");
-
- await CheckProps(priv, new
- {
- _stringField = TString("DerivedClass#_stringField"),
- _dateTime = TDateTime(new DateTime(2020, 7, 6, 5, 4, 3)),
- AutoStringProperty = TString("DerivedClass#AutoStringProperty"),
- StringPropertyForOverrideWithAutoProperty = TString("DerivedClass#StringPropertyForOverrideWithAutoProperty"),
- _base_name = TString("private_name"),
- Base_AutoStringProperty = TString("base#Base_AutoStringProperty"),
- DateTimeForOverride = TGetter("DateTimeForOverride", TDateTime(new DateTime(2190, 9, 7, 5, 3, 2)))
- }, "private");
- });
-
- [ConditionalFact(nameof(RunningOnChrome))]
public async Task StructureGetters() => await CheckInspectLocalsAtBreakpointSite(
"DebuggerTests.StructureGetters", "Evaluate", 2, "Evaluate",
"window.setTimeout(function() { invoke_static_method ('[debugger-test] DebuggerTests.StructureGetters:Evaluate'); })",
var (_, res) = await EvaluateOnCallFrame(id, "test.GetDefaultAndRequiredParamMixedTypes(\"a\", 23, true, 1.23f)", expect_ok: false);
Assert.Contains("method 'test.GetDefaultAndRequiredParamMixedTypes(\"a\", 23, true, 1.23f)' - too many arguments passed", res.Error["message"]?.Value<string>());
- });
+ });
[Fact]
public async Task EvaluateMethodWithLinq() => await CheckInspectLocalsAtBreakpointSite(
await EvaluateOnCallFrameAndCheck(id,
("test.listToLinq.ToList()", TObject("System.Collections.Generic.List<int>", description: "Count = 11"))
);
- });
+ });
}
}
{"Base_GetterForOverrideWithField", (TString("DerivedClass#Base_GetterForOverrideWithField"), true)},
{"BaseBase_MemberForOverride", (TString("DerivedClass#BaseBase_MemberForOverride"), true)},
+ // protected
+ {"b", (TBool(true), true)},
+
// indexers don't show up in getprops
// {"Item", (TSymbol("int { get; }"), true)},
// inherited private
{"_base_name", (TString("private_name"), false)},
{"_base_dateTime", (TGetter("_base_dateTime"), false)},
+ {"_base_autoProperty", (TString("private_autoproperty"), false)},
// inherited public
{"Base_AutoStringProperty", (TString("base#Base_AutoStringProperty"), false)},
{"FirstName", (TGetter("FirstName"), true)},
{"LastName", (TGetter("LastName"), true)},
+ // protected
+ {"b", (TBool(true), true)},
+
// indexers don't show up in getprops
// {"Item", (TSymbol("int { get; }"), true)}
};
}
}
+ public static TheoryData<Dictionary<string, JObject>, Dictionary<string, JObject>, Dictionary<string, JObject>, string> GetDataForProtectionLevels()
+ {
+ var data = new TheoryData<Dictionary<string, JObject>, Dictionary<string, JObject>, Dictionary<string, JObject>, string>();
+ // object DerivedClass; should be 23 elements:
+ var public_props = new Dictionary<string, JObject>()
+ {
+ // own
+ {"a", TNumber(4)},
+ {"DateTime", TGetter("DateTime")},
+ {"AutoStringProperty", TString("DerivedClass#AutoStringProperty")},
+ {"FirstName", TGetter("FirstName")},
+ {"DateTimeForOverride", TGetter("DateTimeForOverride")},
+
+ {"StringPropertyForOverrideWithAutoProperty", TString("DerivedClass#StringPropertyForOverrideWithAutoProperty")},
+ {"Base_AutoStringPropertyForOverrideWithField", TString("DerivedClass#Base_AutoStringPropertyForOverrideWithField")},
+ {"Base_GetterForOverrideWithField", TString("DerivedClass#Base_GetterForOverrideWithField")},
+ {"BaseBase_MemberForOverride", TString("DerivedClass#BaseBase_MemberForOverride")},
+
+ // inherited public
+ {"Base_AutoStringProperty", TString("base#Base_AutoStringProperty")},
+ {"LastName", TGetter("LastName")}
+ };
+
+ var internal_protected_props = new Dictionary<string, JObject>(){
+ // internal
+ {"b", TBool(true)},
+ // inherited protected
+ {"base_num", TNumber(5)}
+ };
+
+ var private_props = new Dictionary<string, JObject>(){
+ {"_stringField", TString("DerivedClass#_stringField")},
+ {"_dateTime", TDateTime(new DateTime(2020, 7, 6, 5, 4, 3))},
+ {"_DTProp", TGetter("_DTProp")},
+
+ // inherited
+ {"_base_name", TString("private_name")},
+ {"_base_autoProperty", TString("private_autoproperty")},
+ {"_base_dateTime", TGetter("_base_dateTime")}
+ };
+ data.Add(public_props, internal_protected_props, private_props, "DerivedClass");
+
+ // structure CloneableStruct:
+ public_props = new Dictionary<string, JObject>()
+ {
+ // own
+ {"a", TNumber(4)},
+ {"DateTime", TGetter("DateTime")},
+ {"AutoStringProperty", TString("CloneableStruct#AutoStringProperty")},
+ {"FirstName", TGetter("FirstName")},
+ {"LastName", TGetter("LastName")}
+ };
+ internal_protected_props = new Dictionary<string, JObject>()
+ {
+ // internal
+ {"b", TBool(true)}
+ };
+ private_props = new Dictionary<string, JObject>()
+ {
+ {"_stringField", TString("CloneableStruct#_stringField")},
+ {"_dateTime", TDateTime(new DateTime(2020, 7, 6, 5, 4, 3 + 3))},
+ {"_DTProp", TGetter("_DTProp")}
+ };
+ data.Add(public_props, internal_protected_props, private_props, "CloneableStruct");
+ return data;
+ }
+
+ [ConditionalTheory(nameof(RunningOnChrome))]
+ [MemberData(nameof(GetDataForProtectionLevels))]
+ public async Task PropertiesSortedByProtectionLevel(
+ Dictionary<string, JObject> expectedPublic, Dictionary<string, JObject> expectedProtInter, Dictionary<string, JObject> expectedPriv, string entryMethod) =>
+ await CheckInspectLocalsAtBreakpointSite(
+ $"DebuggerTests.GetPropertiesTests.{entryMethod}", "InstanceMethod", 1, "InstanceMethod",
+ $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test] DebuggerTests.GetPropertiesTests.{entryMethod}:run'); }})",
+ wait_for_event_fn: async (pause_location) =>
+ {
+ var id = pause_location["callFrames"][0]["callFrameId"].Value<string>();
+ var (obj, _) = await EvaluateOnCallFrame(id, "this");
+ var (pub, internalAndProtected, priv) = await GetPropertiesSortedByProtectionLevels(obj["objectId"]?.Value<string>());
+
+ await CheckProps(pub, expectedPublic, "public");
+ await CheckProps(internalAndProtected, expectedProtInter, "internalAndProtected");
+ await CheckProps(priv, expectedPriv, "private");
+ });
+
}
}
textListOfLists = new List<List<string>> { textList, textList };
idx0 = 0;
idx1 = 1;
- }
+ }
}
public static void EvaluateLocals()
}
}
- public static class EvaluateBrowsableProperties
+ public struct SampleStructure
+ {
+ public SampleStructure() { }
+
+ public int Id = 100;
+
+ internal bool IsStruct = true;
+ }
+
+ public enum SampleEnum
+ {
+ yes = 0,
+ no = 1
+ }
+
+ public class SampleClass
+ {
+ public int ClassId = 200;
+ public List<string> Items = new List<string> { "should not be expanded" };
+ }
+
+ public static class EvaluateBrowsableClass
{
public class TestEvaluateFieldsNone
{
public List<int> list = new List<int>() { 1, 2 };
public int[] array = new int[] { 11, 22 };
public string text = "text";
+ public bool[] nullNone = null;
+ public SampleEnum valueTypeEnum = new();
+ public SampleStructure sampleStruct = new();
+ public SampleClass sampleClass = new();
}
public class TestEvaluatePropertiesNone
public List<int> list { get; set; }
public int[] array { get; set; }
public string text { get; set; }
-
+ public bool[] nullNone { get; set; }
+ public SampleEnum valueTypeEnum { get; set; }
+ public SampleStructure sampleStruct { get; set; }
+ public SampleClass sampleClass { get; set; }
+
public TestEvaluatePropertiesNone()
{
list = new List<int>() { 1, 2 };
array = new int[] { 11, 22 };
text = "text";
+ nullNone = null;
+ valueTypeEnum = new();
+ sampleStruct = new();
+ sampleClass = new();
}
}
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
public string textNever = "textNever";
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public bool[] nullNever = null;
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleEnum valueTypeEnumNever = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleStructure sampleStructNever = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleClass sampleClassNever = new();
}
public class TestEvaluatePropertiesNever
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
public string textNever { get; set; }
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public bool[] nullNever { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleEnum valueTypeEnumNever { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleStructure sampleStructNever { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleClass sampleClassNever { get; set; }
+
public TestEvaluatePropertiesNever()
{
listNever = new List<int>() { 1, 2 };
arrayNever = new int[] { 11, 22 };
textNever = "textNever";
+ nullNever = null;
+ valueTypeEnumNever = new();
+ sampleStructNever = new();
+ sampleClassNever = new();
}
}
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
public string textCollapsed = "textCollapsed";
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public bool[] nullCollapsed = null;
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleEnum valueTypeEnumCollapsed = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleStructure sampleStructCollapsed = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleClass sampleClassCollapsed = new();
}
public class TestEvaluatePropertiesCollapsed
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
public string textCollapsed { get; set; }
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public bool[] nullCollapsed { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleEnum valueTypeEnumCollapsed { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleStructure sampleStructCollapsed { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleClass sampleClassCollapsed { get; set; }
+
public TestEvaluatePropertiesCollapsed()
{
listCollapsed = new List<int>() { 1, 2 };
arrayCollapsed = new int[] { 11, 22 };
textCollapsed = "textCollapsed";
+ nullCollapsed = null;
+ valueTypeEnumCollapsed = new();
+ sampleStructCollapsed = new();
+ sampleClassCollapsed = new();
}
}
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
public string textRootHidden = "textRootHidden";
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public bool[] nullRootHidden = null;
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleEnum valueTypeEnumRootHidden = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleStructure sampleStructRootHidden = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleClass sampleClassRootHidden = new();
}
public class TestEvaluatePropertiesRootHidden
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
public string textRootHidden { get; set; }
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public bool[] nullRootHidden { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleEnum valueTypeEnumRootHidden { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleStructure sampleStructRootHidden { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleClass sampleClassRootHidden { get; set; }
+
+ public TestEvaluatePropertiesRootHidden()
+ {
+ listRootHidden = new List<int>() { 1, 2 };
+ arrayRootHidden = new int[] { 11, 22 };
+ textRootHidden = "textRootHidden";
+ nullRootHidden = null;
+ valueTypeEnumRootHidden = new();
+ sampleStructRootHidden = new();
+ sampleClassRootHidden = new();
+ }
+ }
+
+ public static void Evaluate()
+ {
+ var testFieldsNone = new TestEvaluateFieldsNone();
+ var testFieldsNever = new TestEvaluateFieldsNever();
+ var testFieldsCollapsed = new TestEvaluateFieldsCollapsed();
+ var testFieldsRootHidden = new TestEvaluateFieldsRootHidden();
+
+ var testPropertiesNone = new TestEvaluatePropertiesNone();
+ var testPropertiesNever = new TestEvaluatePropertiesNever();
+ var testPropertiesCollapsed = new TestEvaluatePropertiesCollapsed();
+ var testPropertiesRootHidden = new TestEvaluatePropertiesRootHidden();
+ }
+ }
+
+ public static class EvaluateBrowsableStruct
+ {
+ public struct TestEvaluateFieldsNone
+ {
+ public TestEvaluateFieldsNone() {}
+ public List<int> list = new List<int>() { 1, 2 };
+ public int[] array = new int[] { 11, 22 };
+ public string text = "text";
+ public bool[] nullNone = null;
+ public SampleEnum valueTypeEnum = new();
+ public SampleStructure sampleStruct = new();
+ public SampleClass sampleClass = new();
+ }
+
+ public struct TestEvaluatePropertiesNone
+ {
+ public List<int> list { get; set; }
+ public int[] array { get; set; }
+ public string text { get; set; }
+ public bool[] nullNone { get; set; }
+ public SampleEnum valueTypeEnum { get; set; }
+ public SampleStructure sampleStruct { get; set; }
+ public SampleClass sampleClass { get; set; }
+
+ public TestEvaluatePropertiesNone()
+ {
+ list = new List<int>() { 1, 2 };
+ array = new int[] { 11, 22 };
+ text = "text";
+ nullNone = null;
+ valueTypeEnum = new();
+ sampleStruct = new();
+ sampleClass = new();
+ }
+ }
+
+ public struct TestEvaluateFieldsNever
+ {
+ public TestEvaluateFieldsNever() {}
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public List<int> listNever = new List<int>() { 1, 2 };
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public int[] arrayNever = new int[] { 11, 22 };
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public string textNever = "textNever";
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public bool[] nullNever = null;
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleEnum valueTypeEnumNever = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleStructure sampleStructNever = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleClass sampleClassNever = new();
+ }
+
+ public struct TestEvaluatePropertiesNever
+ {
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public List<int> listNever { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public int[] arrayNever { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public string textNever { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public bool[] nullNever { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleEnum valueTypeEnumNever { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleStructure sampleStructNever { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleClass sampleClassNever { get; set; }
+
+ public TestEvaluatePropertiesNever()
+ {
+ listNever = new List<int>() { 1, 2 };
+ arrayNever = new int[] { 11, 22 };
+ textNever = "textNever";
+ nullNever = null;
+ valueTypeEnumNever = new();
+ sampleStructNever = new();
+ sampleClassNever = new();
+ }
+ }
+
+ public struct TestEvaluateFieldsCollapsed
+ {
+ public TestEvaluateFieldsCollapsed() {}
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public List<int> listCollapsed = new List<int>() { 1, 2 };
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public int[] arrayCollapsed = new int[] { 11, 22 };
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public string textCollapsed = "textCollapsed";
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public bool[] nullCollapsed = null;
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleEnum valueTypeEnumCollapsed = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleStructure sampleStructCollapsed = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleClass sampleClassCollapsed = new();
+ }
+
+ public struct TestEvaluatePropertiesCollapsed
+ {
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public List<int> listCollapsed { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public int[] arrayCollapsed { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public string textCollapsed { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public bool[] nullCollapsed { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleEnum valueTypeEnumCollapsed { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleStructure sampleStructCollapsed { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleClass sampleClassCollapsed { get; set; }
+
+ public TestEvaluatePropertiesCollapsed()
+ {
+ listCollapsed = new List<int>() { 1, 2 };
+ arrayCollapsed = new int[] { 11, 22 };
+ textCollapsed = "textCollapsed";
+ nullCollapsed = null;
+ valueTypeEnumCollapsed = new();
+ sampleStructCollapsed = new();
+ sampleClassCollapsed = new();
+ }
+ }
+
+ public struct TestEvaluateFieldsRootHidden
+ {
+ public TestEvaluateFieldsRootHidden() {}
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public List<int> listRootHidden = new List<int>() { 1, 2 };
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public int[] arrayRootHidden = new int[] { 11, 22 };
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public string textRootHidden = "textRootHidden";
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public bool[] nullRootHidden = null;
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleEnum valueTypeEnumRootHidden = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleStructure sampleStructRootHidden = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleClass sampleClassRootHidden = new();
+ }
+
+ public struct TestEvaluatePropertiesRootHidden
+ {
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public List<int> listRootHidden { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public int[] arrayRootHidden { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public string textRootHidden { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public bool[] nullRootHidden { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleEnum valueTypeEnumRootHidden { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleStructure sampleStructRootHidden { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleClass sampleClassRootHidden { get; set; }
+
public TestEvaluatePropertiesRootHidden()
{
listRootHidden = new List<int>() { 1, 2 };
arrayRootHidden = new int[] { 11, 22 };
textRootHidden = "textRootHidden";
+ nullRootHidden = null;
+ valueTypeEnumRootHidden = new();
+ sampleStructRootHidden = new();
+ sampleClassRootHidden = new();
}
}
}
}
- public static class EvaluateBrowsableStaticProperties
+ public static class EvaluateBrowsableStaticClass
{
public class TestEvaluateFieldsNone
{
public static List<int> list = new List<int>() { 1, 2 };
public static int[] array = new int[] { 11, 22 };
public static string text = "text";
+
+ public static bool[] nullNone = null;
+ public static SampleEnum valueTypeEnum = new();
+ public static SampleStructure sampleStruct = new();
+ public static SampleClass sampleClass = new();
}
public class TestEvaluatePropertiesNone
public static List<int> list { get; set; }
public static int[] array { get; set; }
public static string text { get; set; }
-
+ public static bool[] nullNone { get; set; }
+ public static SampleEnum valueTypeEnum { get; set; }
+ public static SampleStructure sampleStruct { get; set; }
+ public static SampleClass sampleClass { get; set; }
+
public TestEvaluatePropertiesNone()
{
list = new List<int>() { 1, 2 };
array = new int[] { 11, 22 };
text = "text";
+ nullNone = null;
+ valueTypeEnum = new();
+ sampleStruct = new();
+ sampleClass = new();
}
}
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
public static string textNever = "textNever";
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public static bool[] nullNever = null;
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public static SampleEnum valueTypeEnumNever = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public static SampleStructure sampleStructNever = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public static SampleClass sampleClassNever = new();
}
public class TestEvaluatePropertiesNever
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
public static string textNever { get; set; }
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public static bool[] nullNever { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public static SampleEnum valueTypeEnumNever { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public static SampleStructure sampleStructNever { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public static SampleClass sampleClassNever { get; set; }
+
public TestEvaluatePropertiesNever()
{
listNever = new List<int>() { 1, 2 };
arrayNever = new int[] { 11, 22 };
textNever = "textNever";
+ nullNever = null;
+ valueTypeEnumNever = new();
+ sampleStructNever = new();
+ sampleClassNever = new();
}
}
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
public static string textCollapsed = "textCollapsed";
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public static bool[] nullCollapsed = null;
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public static SampleEnum valueTypeEnumCollapsed = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public static SampleStructure sampleStructCollapsed = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public static SampleClass sampleClassCollapsed = new();
}
public class TestEvaluatePropertiesCollapsed
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
public static string textCollapsed { get; set; }
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public static bool[] nullCollapsed { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public static SampleEnum valueTypeEnumCollapsed { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public static SampleStructure sampleStructCollapsed { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public static SampleClass sampleClassCollapsed { get; set; }
+
public TestEvaluatePropertiesCollapsed()
{
listCollapsed = new List<int>() { 1, 2 };
arrayCollapsed = new int[] { 11, 22 };
textCollapsed = "textCollapsed";
+ nullCollapsed = null;
+ valueTypeEnumCollapsed = new();
+ sampleStructCollapsed = new();
+ sampleClassCollapsed = new();
}
}
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
public static string textRootHidden = "textRootHidden";
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public static bool[] nullRootHidden = null;
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public static SampleEnum valueTypeEnumRootHidden = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public static SampleStructure sampleStructRootHidden = new();
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public static SampleClass sampleClassRootHidden = new();
}
public class TestEvaluatePropertiesRootHidden
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
public static string textRootHidden { get; set; }
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public static bool[] nullRootHidden { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public static SampleEnum valueTypeEnumRootHidden { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public static SampleStructure sampleStructRootHidden { get; set; }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public static SampleClass sampleClassRootHidden { get; set; }
+
public TestEvaluatePropertiesRootHidden()
{
listRootHidden = new List<int>() { 1, 2 };
arrayRootHidden = new int[] { 11, 22 };
textRootHidden = "textRootHidden";
+ nullRootHidden = null;
+ valueTypeEnumRootHidden = new();
+ sampleStructRootHidden = new();
+ sampleClassRootHidden = new();
}
}
}
}
- public static class EvaluateBrowsableCustomProperties
+ public static class EvaluateBrowsableCustomPropertiesClass
{
public class TestEvaluatePropertiesNone
{
public List<int> list { get { return new List<int>() { 1, 2 }; } }
public int[] array { get { return new int[] { 11, 22 }; } }
public string text { get { return "text"; } }
+ public bool[] nullNone { get { return null; } }
+ public SampleEnum valueTypeEnum { get { return new(); } }
+ public SampleStructure sampleStruct { get { return new(); } }
+ public SampleClass sampleClass { get { return new(); } }
}
public class TestEvaluatePropertiesNever
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
public string textNever { get { return "textNever"; } }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public bool[] nullNever { get { return null; } }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleEnum valueTypeEnumNever { get { return new(); } }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleStructure sampleStructNever { get { return new(); } }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
+ public SampleClass sampleClassNever { get { return new(); } }
}
public class TestEvaluatePropertiesCollapsed
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
public string textCollapsed { get { return "textCollapsed"; } }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public bool[] nullCollapsed { get { return null; } }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleEnum valueTypeEnumCollapsed { get { return new(); } }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleStructure sampleStructCollapsed { get { return new(); } }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Collapsed)]
+ public SampleClass sampleClassCollapsed { get { return new(); } }
}
public class TestEvaluatePropertiesRootHidden
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
public string textRootHidden { get { return "textRootHidden"; } }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public bool[] nullRootHidden { get { return null; } }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleEnum valueTypeEnumRootHidden { get { return new(); } }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleStructure sampleStructRootHidden { get { return new(); } }
+
+ [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
+ public SampleClass sampleClassRootHidden { get { return new(); } }
}
public static void Evaluate()
public double GetDouble(double param = 1.23) => param;
public string GetString(string param = "1.23") => param;
public string GetUnicodeString(string param = "żółć") => param;
-
- #nullable enable
+
+#nullable enable
public bool? GetBoolNullable(bool? param = true) => param;
public char? GetCharNullable(char? param = 'T') => param;
public byte? GetByteNullable(byte? param = 1) => param;
public float? GetSingleNullable(float? param = 1.23f) => param;
public double? GetDoubleNullable(double? param = 1.23) => param;
public string? GetStringNullable(string? param = "1.23") => param;
- #nullable disable
+#nullable disable
public bool GetNull(object param = null) => param == null ? true : false;
public int GetDefaultAndRequiredParam(int requiredParam, int optionalParam = 3) => requiredParam + optionalParam;
{
var stopHere = true;
}
-
+
public static class NestedClass1
{
public static class NestedClass2
{
private string _base_name;
private DateTime _base_dateTime => new DateTime(2134, 5, 7, 1, 9, 2);
+ private string _base_autoProperty { get; set; }
protected int base_num;
public string Base_AutoStringProperty { get; set; }
public BaseClass()
{
_base_name = "private_name";
+ _base_autoProperty = "private_autoproperty";
base_num = 5;
Base_AutoStringProperty = "base#Base_AutoStringProperty";
DateTimeForOverride = new DateTime(2250, 4, 5, 6, 7, 8);
private DateTime _dateTime = new DateTime(2020, 7, 6, 5, 4, 3);
private DateTime _DTProp => new DateTime(2200, 5, 6, 7, 8, 9);
+ internal bool b = true;
+
public int a;
public DateTime DateTime => _DTProp.AddMinutes(10);
public string AutoStringProperty { get; set; }
private string _stringField;
private DateTime _dateTime;
private DateTime _DTProp => new DateTime(2200, 5, 6, 7, 8, 9);
+
+ internal bool b = true;
public int a;
public DateTime DateTime => _DTProp.AddMinutes(10);