Browse Source

Show the type-forwarder bit in TypeAttributes tooltips

0x00200000 is the ECMA-335 Forwarder bit (II.23.1.15), set on
ExportedType rows that forward a type to another assembly.
System.Reflection.TypeAttributes has no member for it, so the
enum-driven flag enumeration left it invisible in the Flags group.

Assisted-by: Claude:claude-fable-5[1m]:Claude Code
pull/3759/head
Siegfried Pammer 4 weeks ago
parent
commit
9533d0ca8e
  1. 23
      ILSpy.Tests/Metadata/FlagsTooltipTests.cs
  2. 11
      ILSpy/Metadata/FlagsTooltip.cs

23
ILSpy.Tests/Metadata/FlagsTooltipTests.cs

@ -59,6 +59,29 @@ public class FlagsTooltipTests @@ -59,6 +59,29 @@ public class FlagsTooltipTests
group.SelectedFlag.Name.Should().StartWith("Public");
}
[AvaloniaTest]
public void ForTypeAttributes_Includes_The_Type_Forwarder_Bit()
{
// 0x00200000 is the ECMA-335 Forwarder bit (II.23.1.15), set on type-forwarder
// ExportedType rows. System.Reflection.TypeAttributes has no member for it, so the
// enum-driven flag enumeration alone would leave it invisible in the tooltip.
var tooltip = FlagsTooltip.ForTypeAttributes((TypeAttributes)0x00200000);
var flags = tooltip.Groups.OfType<MultipleChoiceGroup>().Single().Flags;
var forwarder = flags.Single(f => f.Name.StartsWith("IsTypeForwarder"));
forwarder.IsSelected.Should().BeTrue("the Forwarder bit is set in the value");
}
[AvaloniaTest]
public void ForTypeAttributes_Leaves_The_Type_Forwarder_Bit_Unchecked_When_Clear()
{
var tooltip = FlagsTooltip.ForTypeAttributes(TypeAttributes.Public | TypeAttributes.Sealed);
var flags = tooltip.Groups.OfType<MultipleChoiceGroup>().Single().Flags;
var forwarder = flags.Single(f => f.Name.StartsWith("IsTypeForwarder"));
forwarder.IsSelected.Should().BeFalse("the Forwarder bit is not set in the value");
}
[AvaloniaTest]
public void MetadataCellTooltip_Renders_A_FlagsTooltip_As_A_Control()
{

11
ILSpy/Metadata/FlagsTooltip.cs

@ -74,13 +74,22 @@ namespace ILSpy.Metadata @@ -74,13 +74,22 @@ namespace ILSpy.Metadata
public static FlagsTooltip ForTypeAttributes(TypeAttributes attributes)
{
const TypeAttributes otherFlagsMask = ~(TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.ClassSemanticsMask | TypeAttributes.StringFormatMask | TypeAttributes.CustomFormatMask);
// ECMA-335 II.23.1.15 Forwarder: set on ExportedType rows that forward the type to
// another assembly. System.Reflection.TypeAttributes has no member for the bit, so
// the enum-driven GetFlags enumeration cannot surface it; inject it explicitly.
const TypeAttributes isTypeForwarder = (TypeAttributes)0x00200000;
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),
new MultipleChoiceGroup(
FlagGroup.GetFlags(typeof(TypeAttributes), (int)otherFlagsMask, (int)(attributes & otherFlagsMask))
.Append(new Flag($"IsTypeForwarder ({(int)isTypeForwarder:X4})", (int)isTypeForwarder, (attributes & isTypeForwarder) != 0))) {
Header = "Flags:",
SelectedFlags = (int)(attributes & otherFlagsMask),
},
};
}
}

Loading…
Cancel
Save