Skip to content

Commit 7574e03

Browse files
ilonatommyradical
andauthored
[wasm][debugger] Add Browsable Attribute support. (#62045)
* Description of DebuggerBrowsable behavior. * Added test for browse attributes. * Corrected typos in the doc. * Added Browse Never feature. Corrected Collapse test. ToDo: RootHidden. * Draft of RootHidden solution. * Added Array to test cases as it behaves differently than Collection. * Added name concatenation to make array/list elemetns in debug window unique. * Update docs/design/mono/debugger.md Co-authored-by: Ankit Jain <radical@gmail.com> * Applied PR review suggestions. * Added a reference to regular Browsable attribute behavior in .net. * Applied most of review suggestions. * Stopping GetFieldsValue early. * Remove unintentional change to the original code. * Do not skip fields that don't have browsable attributes. * Changing the expected behavior to match Console Application. EventHandlers are Browsable.Never by default. * Changed the place of checking if objetc is an array. * Update src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs Co-authored-by: Ankit Jain <radical@gmail.com> * Removed unused variables. * Removing space and unused import. * Partially addressed @radical comments. * Addressed the comment about extension instead of Union. * Removed string cultural vunerability. * Added Properties dictionary, the same as for fields. * Fixed the bug I made by using dynamc. * Applying @radical comments about refactoring. * Corrected typo. * Added tests for properties. * Draft of changes for properties handling - never and root hidden failing. * Fix for RootHidden properties. * Added tests for static fields decorated with Browsable. * Correct a typo. * Undo merge unintentional changes. * Changing expected behavior for MulticastDelegateTest - in Console Application EventHandler is Browsable.Never by default so we should not expect it to be visible in the debug window. * Removing not relevant changes created after merge with main. * Remove file added in merge with main. * Revert "Removing not relevant changes created after merge with main." This reverts commit b1acf8b. * Revert. * Revert revert. * One broken test for custom getter. * Ugly fix to make all the tests work. * Refactored JArray aggregation to Dictionary. * Better naming. * Remove not connected to PR file. * Applied @thaystg suggestions. * Removed comments. Co-authored-by: Ankit Jain <radical@gmail.com>
1 parent 2a11aab commit 7574e03

File tree

7 files changed

+730
-90
lines changed

7 files changed

+730
-90
lines changed

docs/design/mono/debugger.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,11 @@ Web Assembly Debugger supports usage of following attributes:
1818
- Stepping In/Over: results in an additional stepping need to proceed to the next line.<br><br>
1919
- __System.Diagnostics.DebuggerDisplay__
2020
- __System.Diagnostics.DebuggerTypeProxy__
21-
- ...
21+
- __System.Diagnostics.DebuggerBrowsable__ ([doc](https://docs.microsoft.com/en-us/dotnet/api/system.diagnostics.debuggerbrowsableattribute?view=net-6.0))
22+
- Collapsed - displayed normally.
23+
- RootHidden:
24+
- Simple type - not displayed in the debugger window.
25+
- Collection / Array - the values of a collection are displayed in a flat view, using the naming convention: *rootName[idx]*.
26+
27+
- Never - not displayed in the debugger window.
28+

src/mono/wasm/debugger/BrowserDebugProxy/DebugStore.cs

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
using System.IO.Compression;
2222
using System.Reflection;
2323
using System.Collections.Immutable;
24+
using System.Diagnostics;
25+
using Microsoft.VisualBasic;
2426

2527
namespace Microsoft.WebAssembly.Diagnostics
2628
{
@@ -475,14 +477,19 @@ public VarInfo[] GetLiveVarsAt(int offset)
475477

476478
internal class TypeInfo
477479
{
480+
private readonly ILogger logger;
478481
internal AssemblyInfo assembly;
479482
private TypeDefinition type;
480483
private List<MethodInfo> methods;
481484
internal int Token { get; }
482485
internal string Namespace { get; }
483486

484-
public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefinition type)
487+
public Dictionary<string, DebuggerBrowsableState?> DebuggerBrowsableFields = new();
488+
public Dictionary<string, DebuggerBrowsableState?> DebuggerBrowsableProperties = new();
489+
490+
public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefinition type, ILogger logger)
485491
{
492+
this.logger = logger;
486493
this.assembly = assembly;
487494
var metadataReader = assembly.asmMetadataReader;
488495
Token = MetadataTokens.GetToken(metadataReader, typeHandle);
@@ -500,6 +507,63 @@ public TypeInfo(AssemblyInfo assembly, TypeDefinitionHandle typeHandle, TypeDefi
500507
FullName = Namespace + "." + Name;
501508
else
502509
FullName = Name;
510+
511+
foreach (var field in type.GetFields())
512+
{
513+
try
514+
{
515+
var fieldDefinition = metadataReader.GetFieldDefinition(field);
516+
var fieldName = metadataReader.GetString(fieldDefinition.Name);
517+
AppendToBrowsable(DebuggerBrowsableFields, fieldDefinition.GetCustomAttributes(), fieldName);
518+
}
519+
catch (Exception ex)
520+
{
521+
logger.LogDebug($"Failed to read browsable attributes of a field. ({ex.Message})");
522+
continue;
523+
}
524+
}
525+
526+
foreach (var prop in type.GetProperties())
527+
{
528+
try
529+
{
530+
var propDefinition = metadataReader.GetPropertyDefinition(prop);
531+
var propName = metadataReader.GetString(propDefinition.Name);
532+
AppendToBrowsable(DebuggerBrowsableProperties, propDefinition.GetCustomAttributes(), propName);
533+
}
534+
catch (Exception ex)
535+
{
536+
logger.LogDebug($"Failed to read browsable attributes of a property. ({ex.Message})");
537+
continue;
538+
}
539+
}
540+
541+
void AppendToBrowsable(Dictionary<string, DebuggerBrowsableState?> dict, CustomAttributeHandleCollection customAttrs, string fieldName)
542+
{
543+
foreach (var cattr in customAttrs)
544+
{
545+
try
546+
{
547+
var ctorHandle = metadataReader.GetCustomAttribute(cattr).Constructor;
548+
if (ctorHandle.Kind != HandleKind.MemberReference)
549+
continue;
550+
var container = metadataReader.GetMemberReference((MemberReferenceHandle)ctorHandle).Parent;
551+
var valueBytes = metadataReader.GetBlobBytes(metadataReader.GetCustomAttribute(cattr).Value);
552+
var attributeName = metadataReader.GetString(metadataReader.GetTypeReference((TypeReferenceHandle)container).Name);
553+
if (attributeName != "DebuggerBrowsableAttribute")
554+
continue;
555+
var state = (DebuggerBrowsableState)valueBytes[2];
556+
if (!Enum.IsDefined(typeof(DebuggerBrowsableState), state))
557+
continue;
558+
dict.Add(fieldName, state);
559+
break;
560+
}
561+
catch
562+
{
563+
continue;
564+
}
565+
}
566+
}
503567
}
504568

505569
public TypeInfo(AssemblyInfo assembly, string name)
@@ -515,7 +579,6 @@ public TypeInfo(AssemblyInfo assembly, string name)
515579
public override string ToString() => "TypeInfo('" + FullName + "')";
516580
}
517581

518-
519582
internal class AssemblyInfo
520583
{
521584
private static int next_id;
@@ -652,7 +715,7 @@ SourceFile FindSource(DocumentHandle doc, int rowid, string documentName)
652715
{
653716
var typeDefinition = asmMetadataReader.GetTypeDefinition(type);
654717

655-
var typeInfo = new TypeInfo(this, type, typeDefinition);
718+
var typeInfo = new TypeInfo(this, type, typeDefinition, logger);
656719
TypesByName[typeInfo.FullName] = typeInfo;
657720
TypesByToken[typeInfo.Token] = typeInfo;
658721
if (pdbMetadataReader != null)
@@ -680,7 +743,6 @@ SourceFile FindSource(DocumentHandle doc, int rowid, string documentName)
680743
}
681744
}
682745
}
683-
684746
}
685747

686748
private void ProcessSourceLink()

0 commit comments

Comments
 (0)