diff --git a/ICSharpCode.Decompiler/NRExtensions.cs b/ICSharpCode.Decompiler/NRExtensions.cs index db299ee9a..f3cc16fc5 100644 --- a/ICSharpCode.Decompiler/NRExtensions.cs +++ b/ICSharpCode.Decompiler/NRExtensions.cs @@ -50,7 +50,7 @@ namespace ICSharpCode.Decompiler public static bool HasGeneratedName(this IType type) { - return type.Name.StartsWith("<", StringComparison.Ordinal) || type.Name.Contains("<"); + return SRMExtensions.IsGeneratedName(type.Name); } public static bool IsAnonymousType(this IType type) diff --git a/ICSharpCode.Decompiler/SRMExtensions.cs b/ICSharpCode.Decompiler/SRMExtensions.cs index 2be174f6c..bcd544fb1 100644 --- a/ICSharpCode.Decompiler/SRMExtensions.cs +++ b/ICSharpCode.Decompiler/SRMExtensions.cs @@ -489,9 +489,20 @@ namespace ICSharpCode.Decompiler public static bool IsGeneratedName(this StringHandle handle, MetadataReader metadata) { - return !handle.IsNil - && (metadata.GetString(handle).StartsWith("<", StringComparison.Ordinal) - || metadata.GetString(handle).Contains("$")); + return !handle.IsNil && IsGeneratedName(metadata.GetString(handle)); + } + + /// + /// Detects the mangled names compilers give to entities that have no user-written + /// declaration. The C# compiler prefixes them with '<', the VB compiler separates + /// the parts with '$' (VB$AnonymousType_0, VB$StateMachine_1_Foo). Neither character + /// is legal in a C# or VB identifier. + /// Note that a name may legitimately contain '<' without being generated: explicit + /// implementations of generic interface members are named after the interface. + /// + internal static bool IsGeneratedName(string name) + { + return name.StartsWith("<", StringComparison.Ordinal) || name.Contains("$"); } public static bool HasGeneratedName(this MethodDefinitionHandle handle, MetadataReader metadata)