Skip to content

Commit 5f0e767

Browse files
Fix crash in TryEncodingV2, if there are multiple extension groups with the same target type, but different extension parameter name.
1 parent c2eb3c0 commit 5f0e767

File tree

2 files changed

+82
-27
lines changed

2 files changed

+82
-27
lines changed

ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemTestCase.cs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -785,5 +785,51 @@ public static void GenericMethod<T>(T value)
785785
{
786786
}
787787
}
788+
789+
extension(int number)
790+
{
791+
public int Squared => number * number;
792+
}
793+
794+
extension(string input)
795+
{
796+
public void Method() { }
797+
public void Method(char c) { }
798+
public string AsString => input.ToString();
799+
public string Test {
800+
get => "Test";
801+
set { }
802+
}
803+
public static void StaticMethodOnString() { }
804+
public static void StaticMethodOnString(double x) { }
805+
public static string StaticPropertyOnString => "StaticProperty";
806+
public static void GenericMethodOnString<T>(T value)
807+
{
808+
}
809+
}
810+
811+
extension<T>(T input)
812+
{
813+
public void Method() { }
814+
public void Method(char c) { }
815+
public string AsString => input.ToString();
816+
public string Test {
817+
get => "Test";
818+
set { }
819+
}
820+
public static void StaticMethodOnGeneric() { }
821+
public static void StaticMethodOnGeneric(double x) { }
822+
public static string StaticPropertyOnGeneric => "StaticProperty";
823+
public static void GenericMethodOnGeneric<U>(U value)
824+
{
825+
}
826+
}
827+
828+
extension<T, T2>(T input)
829+
{
830+
public void StaticMethodOnGenericTwoParams(T2 x)
831+
{
832+
}
833+
}
788834
}
789-
}
835+
}

ICSharpCode.Decompiler/TypeSystem/ExtensionInfo.cs

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,14 @@ public ExtensionInfo(MetadataModule module, ITypeDefinition extensionContainer)
4040

4141
var metadata = module.MetadataFile.Metadata;
4242

43-
foreach (var extGroup in extensionContainer.NestedTypes)
43+
foreach (var nestedType in extensionContainer.NestedTypes)
4444
{
45-
if (TryEncodingV1(extGroup))
45+
if (TryEncodingV1(nestedType))
4646
{
4747
continue;
4848
}
4949

50-
TryEncodingV2(extGroup);
50+
TryEncodingV2(nestedType);
5151
}
5252

5353
bool TryEncodingV1(ITypeDefinition extGroup)
@@ -90,43 +90,52 @@ bool TryEncodingV1(ITypeDefinition extGroup)
9090
return true;
9191
}
9292

93-
bool TryEncodingV2(ITypeDefinition extGroup)
93+
bool TryEncodingV2(ITypeDefinition extensionGroupsContainer)
9494
{
95-
if (!(extGroup is { Kind: TypeKind.Class, IsSealed: true }
96-
&& extGroup.Name.StartsWith("<G>$", StringComparison.Ordinal)))
95+
// there exists one nested type per extension target type
96+
if (!(extensionGroupsContainer is { Kind: TypeKind.Class, IsSealed: true }
97+
&& extensionGroupsContainer.Name.StartsWith("<G>$", StringComparison.Ordinal)))
9798
{
9899
return false;
99100
}
100101

101-
var markerType = extGroup.NestedTypes.SingleOrDefault(t => t.Name.StartsWith("<M>$", StringComparison.Ordinal) && t.IsStatic);
102-
var marker = markerType?.Methods.SingleOrDefault(m => m.Name == "<Extension>$" && m.IsStatic && m.Parameters.Count == 1);
102+
// if there are multiple extension-blocks with the same target type,
103+
// but different names for the extension parameter,
104+
// there is a separate markerType, so there are multiple marker types per
105+
// target type
106+
foreach (var markerType in extensionGroupsContainer.NestedTypes)
107+
{
108+
if (!(markerType.Name.StartsWith("<M>$", StringComparison.Ordinal) && markerType.IsStatic))
109+
continue;
110+
var marker = markerType.Methods.SingleOrDefault(m => m.Name == "<Extension>$" && m.IsStatic && m.Parameters.Count == 1);
111+
if (marker == null)
112+
continue;
103113

104-
if (markerType == null || marker == null)
105-
return false;
114+
TypeDefinition td = metadata.GetTypeDefinition((TypeDefinitionHandle)extensionGroupsContainer.MetadataToken);
115+
List<IMethod> extensionMethods = [];
116+
ITypeParameter[] extensionGroupTypeParameters = new ITypeParameter[extensionGroupsContainer.TypeParameterCount];
106117

107-
TypeDefinition td = metadata.GetTypeDefinition((TypeDefinitionHandle)extGroup.MetadataToken);
108-
List<IMethod> extensionMethods = [];
109-
ITypeParameter[] extensionGroupTypeParameters = new ITypeParameter[extGroup.TypeParameterCount];
118+
// For easier access to accessors we use SRM
119+
foreach (var h in td.GetMethods())
120+
{
121+
var method = module.GetDefinition(h);
110122

111-
// For easier access to accessors we use SRM
112-
foreach (var h in td.GetMethods())
113-
{
114-
var method = module.GetDefinition(h);
123+
if (method.SymbolKind is SymbolKind.Constructor)
124+
continue;
115125

116-
if (method.SymbolKind is SymbolKind.Constructor)
117-
continue;
126+
var attribute = method.GetAttribute(KnownAttribute.ExtensionMarker);
127+
if (attribute == null)
128+
continue;
118129

119-
var attribute = method.GetAttribute(KnownAttribute.ExtensionMarker);
120-
if (attribute == null)
121-
continue;
130+
if (attribute.FixedArguments[0].Value?.ToString() != markerType.Name)
131+
continue;
122132

123-
if (attribute.FixedArguments[0].Value?.ToString() != markerType.Name)
124-
continue;
133+
extensionMethods.Add(method);
134+
}
125135

126-
extensionMethods.Add(method);
136+
CollectImplementationMethods(extensionGroupsContainer, marker, extensionMethods, extensionGroupTypeParameters);
127137
}
128138

129-
CollectImplementationMethods(extGroup, marker, extensionMethods, extensionGroupTypeParameters);
130139
return true;
131140
}
132141

0 commit comments

Comments
 (0)