Browse Source

Deduplicate the heap walk and the TypeAttributes tooltip

The #Strings/#US/#Blob nodes each open-coded the same offset-chained
walk, whose subtlety (handle 0 is a real entry despite being the nil
handle) is now documented once in WalkHeap. The TypeDef and
ExportedType entries built byte-identical TypeAttributes flag-group
tooltips; FlagsTooltip.ForTypeAttributes is the shared factory.

Assisted-by: Claude:claude-fable-5[1m]:Claude Code
pull/3759/head
Siegfried Pammer 4 weeks ago
parent
commit
e4078cc28b
  1. 8
      ILSpy/Metadata/BlobHeapTreeNode.cs
  2. 11
      ILSpy/Metadata/CorTables/ExportedTypeTableTreeNode.cs
  3. 11
      ILSpy/Metadata/CorTables/TypeDefTableTreeNode.cs
  4. 19
      ILSpy/Metadata/FlagsTooltip.cs
  5. 19
      ILSpy/Metadata/MetadataHeapTreeNode.cs
  6. 8
      ILSpy/Metadata/StringHeapTreeNode.cs
  7. 8
      ILSpy/Metadata/UserStringHeapTreeNode.cs

8
ILSpy/Metadata/BlobHeapTreeNode.cs

@ -43,12 +43,8 @@ namespace ILSpy.Metadata @@ -43,12 +43,8 @@ namespace ILSpy.Metadata
protected override void LoadEntries(MetadataReader metadata, List<BlobHeapEntry> list)
{
var handle = MetadataTokens.BlobHandle(0);
do
{
list.Add(new BlobHeapEntry(metadata, handle));
handle = metadata.GetNextHandle(handle);
} while (!handle.IsNil);
WalkHeap(list, MetadataTokens.BlobHandle(0),
h => new BlobHeapEntry(metadata, h), metadata.GetNextHandle, h => h.IsNil);
}
public sealed class BlobHeapEntry

11
ILSpy/Metadata/CorTables/ExportedTypeTableTreeNode.cs

@ -63,16 +63,7 @@ namespace ILSpy.Metadata.CorTables @@ -63,16 +63,7 @@ namespace ILSpy.Metadata.CorTables
[ColumnInfo("X8")]
public TypeAttributes Attributes => type.Attributes;
const TypeAttributes otherFlagsMask = ~(TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.ClassSemanticsMask | TypeAttributes.StringFormatMask | TypeAttributes.CustomFormatMask);
public object AttributesTooltip => new FlagsTooltip {
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "Visibility: ", (int)TypeAttributes.VisibilityMask, (int)(type.Attributes & TypeAttributes.VisibilityMask), new Flag("NotPublic (0000)", 0, false), includeAny: false),
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "Class layout: ", (int)TypeAttributes.LayoutMask, (int)(type.Attributes & TypeAttributes.LayoutMask), new Flag("AutoLayout (0000)", 0, false), includeAny: false),
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "Class semantics: ", (int)TypeAttributes.ClassSemanticsMask, (int)(type.Attributes & TypeAttributes.ClassSemanticsMask), new Flag("Class (0000)", 0, false), includeAny: false),
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "String format: ", (int)TypeAttributes.StringFormatMask, (int)(type.Attributes & TypeAttributes.StringFormatMask), new Flag("AnsiClass (0000)", 0, false), includeAny: false),
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "Custom format: ", (int)TypeAttributes.CustomFormatMask, (int)(type.Attributes & TypeAttributes.CustomFormatMask), new Flag("Value0 (0000)", 0, false), includeAny: false),
FlagGroup.CreateMultipleChoiceGroup(typeof(TypeAttributes), "Flags:", (int)otherFlagsMask, (int)(type.Attributes & otherFlagsMask), includeAll: false),
};
public object AttributesTooltip => FlagsTooltip.ForTypeAttributes(type.Attributes);
[ColumnInfo("X8")]
public int TypeDefId => type.GetTypeDefinitionId();

11
ILSpy/Metadata/CorTables/TypeDefTableTreeNode.cs

@ -66,16 +66,7 @@ namespace ILSpy.Metadata.CorTables @@ -66,16 +66,7 @@ namespace ILSpy.Metadata.CorTables
[ColumnInfo("X8")]
public TypeAttributes Attributes => typeDef.Attributes;
const TypeAttributes otherFlagsMask = ~(TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.ClassSemanticsMask | TypeAttributes.StringFormatMask | TypeAttributes.CustomFormatMask);
public object AttributesTooltip => new FlagsTooltip {
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "Visibility: ", (int)TypeAttributes.VisibilityMask, (int)(typeDef.Attributes & TypeAttributes.VisibilityMask), new Flag("NotPublic (0000)", 0, false), includeAny: false),
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "Class layout: ", (int)TypeAttributes.LayoutMask, (int)(typeDef.Attributes & TypeAttributes.LayoutMask), new Flag("AutoLayout (0000)", 0, false), includeAny: false),
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "Class semantics: ", (int)TypeAttributes.ClassSemanticsMask, (int)(typeDef.Attributes & TypeAttributes.ClassSemanticsMask), new Flag("Class (0000)", 0, false), includeAny: false),
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "String format: ", (int)TypeAttributes.StringFormatMask, (int)(typeDef.Attributes & TypeAttributes.StringFormatMask), new Flag("AnsiClass (0000)", 0, false), includeAny: false),
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "Custom format: ", (int)TypeAttributes.CustomFormatMask, (int)(typeDef.Attributes & TypeAttributes.CustomFormatMask), new Flag("Value0 (0000)", 0, false), includeAny: false),
FlagGroup.CreateMultipleChoiceGroup(typeof(TypeAttributes), "Flags:", (int)otherFlagsMask, (int)(typeDef.Attributes & otherFlagsMask), includeAll: false),
};
public object AttributesTooltip => FlagsTooltip.ForTypeAttributes(typeDef.Attributes);
public string Name => metadataFile.Metadata.GetString(typeDef.Name);

19
ILSpy/Metadata/FlagsTooltip.cs

@ -64,6 +64,25 @@ namespace ILSpy.Metadata @@ -64,6 +64,25 @@ namespace ILSpy.Metadata
panel.Children.Add(group.Build());
return panel;
}
/// <summary>
/// Tooltip for a <see cref="TypeAttributes"/> column: one single-choice group per
/// mutually exclusive sub-range (visibility, layout, class semantics, string format,
/// custom format) plus a multiple-choice group for the remaining independent bits.
/// Shared by every table whose rows carry type attributes (TypeDef, ExportedType).
/// </summary>
public static FlagsTooltip ForTypeAttributes(TypeAttributes attributes)
{
const TypeAttributes otherFlagsMask = ~(TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.ClassSemanticsMask | TypeAttributes.StringFormatMask | TypeAttributes.CustomFormatMask);
return new FlagsTooltip {
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "Visibility: ", (int)TypeAttributes.VisibilityMask, (int)(attributes & TypeAttributes.VisibilityMask), new Flag("NotPublic (0000)", 0, false), includeAny: false),
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "Class layout: ", (int)TypeAttributes.LayoutMask, (int)(attributes & TypeAttributes.LayoutMask), new Flag("AutoLayout (0000)", 0, false), includeAny: false),
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "Class semantics: ", (int)TypeAttributes.ClassSemanticsMask, (int)(attributes & TypeAttributes.ClassSemanticsMask), new Flag("Class (0000)", 0, false), includeAny: false),
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "String format: ", (int)TypeAttributes.StringFormatMask, (int)(attributes & TypeAttributes.StringFormatMask), new Flag("AnsiClass (0000)", 0, false), includeAny: false),
FlagGroup.CreateSingleChoiceGroup(typeof(TypeAttributes), "Custom format: ", (int)TypeAttributes.CustomFormatMask, (int)(attributes & TypeAttributes.CustomFormatMask), new Flag("Value0 (0000)", 0, false), includeAny: false),
FlagGroup.CreateMultipleChoiceGroup(typeof(TypeAttributes), "Flags:", (int)otherFlagsMask, (int)(attributes & otherFlagsMask), includeAll: false),
};
}
}
public readonly struct Flag

19
ILSpy/Metadata/MetadataHeapTreeNode.cs

@ -92,5 +92,24 @@ namespace ILSpy.Metadata @@ -92,5 +92,24 @@ namespace ILSpy.Metadata
/// <summary>Materialises every heap row into <paramref name="list"/>.</summary>
protected abstract void LoadEntries(MetadataReader metadata, List<TEntry> list);
/// <summary>
/// Shared walk for the offset-chained heaps (#Strings, #US, #Blob). Handle 0 is a
/// real first entry (the heap's empty/zero slot) even though it is the nil handle,
/// so each entry is added before <paramref name="getNextHandle"/> is consulted; the
/// walk ends when the returned handle is nil.
/// </summary>
protected static void WalkHeap<THandle>(List<TEntry> list, THandle firstHandle,
Func<THandle, TEntry> createEntry, Func<THandle, THandle> getNextHandle,
Predicate<THandle> isNil)
where THandle : struct
{
var handle = firstHandle;
do
{
list.Add(createEntry(handle));
handle = getNextHandle(handle);
} while (!isNil(handle));
}
}
}

8
ILSpy/Metadata/StringHeapTreeNode.cs

@ -43,12 +43,8 @@ namespace ILSpy.Metadata @@ -43,12 +43,8 @@ namespace ILSpy.Metadata
protected override void LoadEntries(MetadataReader metadata, List<StringHeapEntry> list)
{
var handle = MetadataTokens.StringHandle(0);
do
{
list.Add(new StringHeapEntry(metadata, handle));
handle = metadata.GetNextHandle(handle);
} while (!handle.IsNil);
WalkHeap(list, MetadataTokens.StringHandle(0),
h => new StringHeapEntry(metadata, h), metadata.GetNextHandle, h => h.IsNil);
}
public sealed class StringHeapEntry

8
ILSpy/Metadata/UserStringHeapTreeNode.cs

@ -42,12 +42,8 @@ namespace ILSpy.Metadata @@ -42,12 +42,8 @@ namespace ILSpy.Metadata
protected override void LoadEntries(MetadataReader metadata, List<UserStringHeapEntry> list)
{
var handle = MetadataTokens.UserStringHandle(0);
do
{
list.Add(new UserStringHeapEntry(metadata, handle));
handle = metadata.GetNextHandle(handle);
} while (!handle.IsNil);
WalkHeap(list, MetadataTokens.UserStringHandle(0),
h => new UserStringHeapEntry(metadata, h), metadata.GetNextHandle, h => h.IsNil);
}
public sealed class UserStringHeapEntry

Loading…
Cancel
Save