Skip to content

Commit f8dcd95

Browse files
Add support for extensions in CSharpDecompiler
1 parent 9157122 commit f8dcd95

File tree

1 file changed

+77
-19
lines changed

1 file changed

+77
-19
lines changed

ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

Lines changed: 77 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,9 @@ public static bool MemberIsHidden(MetadataFile module, EntityHandle member, Deco
318318
return true;
319319
if (settings.FixedBuffers && name.StartsWith("<", StringComparison.Ordinal) && name.Contains("__FixedBuffer"))
320320
return true;
321-
if (settings.InlineArrays && name.StartsWith("<>y__InlineArray", StringComparison.Ordinal) && name.EndsWith("`1"))
321+
if (settings.InlineArrays && name.StartsWith("<>y__InlineArray", StringComparison.Ordinal) && name.EndsWith("`1", StringComparison.Ordinal))
322+
return true;
323+
if (settings.ExtensionMembers && name.StartsWith("<>E__", StringComparison.Ordinal))
322324
return true;
323325
}
324326
else if (type.IsCompilerGenerated(metadata))
@@ -1037,7 +1039,7 @@ public SyntaxTree Decompile(IEnumerable<EntityHandle> definitions)
10371039
break;
10381040
case HandleKind.MethodDefinition:
10391041
IMethod method = module.GetDefinition((MethodDefinitionHandle)entity);
1040-
syntaxTree.Members.Add(DoDecompile(method, decompileRun, new SimpleTypeResolveContext(method)));
1042+
syntaxTree.Members.Add(DoDecompile(method, decompileRun, new SimpleTypeResolveContext(method), null));
10411043
if (first)
10421044
{
10431045
parentTypeDef = method.DeclaringTypeDefinition;
@@ -1054,7 +1056,7 @@ public SyntaxTree Decompile(IEnumerable<EntityHandle> definitions)
10541056
break;
10551057
case HandleKind.PropertyDefinition:
10561058
IProperty property = module.GetDefinition((PropertyDefinitionHandle)entity);
1057-
syntaxTree.Members.Add(DoDecompile(property, decompileRun, new SimpleTypeResolveContext(property)));
1059+
syntaxTree.Members.Add(DoDecompile(property, decompileRun, new SimpleTypeResolveContext(property), null));
10581060
if (first)
10591061
{
10601062
parentTypeDef = property.DeclaringTypeDefinition;
@@ -1361,14 +1363,44 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
13611363
partialTypeInfo = null;
13621364
}
13631365

1366+
if (settings.ExtensionMembers)
1367+
{
1368+
foreach (var group in typeDef.ExtensionInfo?.GetGroups() ?? [])
1369+
{
1370+
var ext = new ExtensionDeclaration();
1371+
ext.TypeParameters.AddRange(group.Key.DeclaringTypeDefinition.TypeParameters.Select(tp => typeSystemAstBuilder.ConvertTypeParameter(tp)));
1372+
ext.ReceiverParameters.Add(typeSystemAstBuilder.ConvertParameter(group.Key.Parameters.Single()));
1373+
ext.Constraints.AddRange(group.Key.DeclaringTypeDefinition.TypeParameters.Select(c => typeSystemAstBuilder.ConvertTypeParameterConstraint(c)));
1374+
1375+
foreach (var member in group)
1376+
{
1377+
IMember extMember = member.ExtensionMember;
1378+
if (member.ExtensionMember.IsAccessor)
1379+
{
1380+
extMember = member.ExtensionMember.AccessorOwner;
1381+
}
1382+
if (entityMap.Contains(extMember) || extMember.MetadataToken.IsNil)
1383+
{
1384+
// Member is already decompiled.
1385+
continue;
1386+
}
1387+
EntityDeclaration extMemberDecl = DoDecompileExtensionMember(extMember, typeDef.ExtensionInfo, decompileRun, decompilationContext);
1388+
ext.Members.Add(extMemberDecl);
1389+
entityMap.Add(extMember, extMemberDecl);
1390+
}
1391+
1392+
typeDecl.Members.Add(ext);
1393+
}
1394+
}
1395+
13641396
// Decompile members that are not compiler-generated.
13651397
foreach (var entity in allOrderedEntities)
13661398
{
13671399
if (entity.MetadataToken.IsNil || MemberIsHidden(module.MetadataFile, entity.MetadataToken, settings))
13681400
{
13691401
continue;
13701402
}
1371-
DoDecompileMember(entity, recordDecompiler, partialTypeInfo);
1403+
DoDecompileMember(entity, recordDecompiler, partialTypeInfo, typeDef.ExtensionInfo);
13721404
}
13731405

13741406
// Decompile compiler-generated members that are still needed.
@@ -1380,7 +1412,7 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
13801412
// Member is already decompiled.
13811413
continue;
13821414
}
1383-
DoDecompileMember(entity, recordDecompiler, partialTypeInfo);
1415+
DoDecompileMember(entity, recordDecompiler, partialTypeInfo, typeDef.ExtensionInfo);
13841416
}
13851417

13861418
// Add all decompiled members to syntax tree in the correct order.
@@ -1470,13 +1502,18 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
14701502
Instrumentation.DecompilerEventSource.Log.DoDecompileTypeDefinition(typeDef.FullName, watch.ElapsedMilliseconds);
14711503
}
14721504

1473-
void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, PartialTypeInfo partialType)
1505+
void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, PartialTypeInfo partialType, ExtensionInfo extensionInfo)
14741506
{
14751507
if (partialType != null && partialType.IsDeclaredMember(entity.MetadataToken))
14761508
{
14771509
return;
14781510
}
14791511

1512+
if (settings.ExtensionMembers && extensionInfo != null && entity is IMethod m && extensionInfo.InfoOfImplementationMember(m).HasValue)
1513+
{
1514+
return;
1515+
}
1516+
14801517
EntityDeclaration entityDecl;
14811518
switch (entity)
14821519
{
@@ -1497,15 +1534,15 @@ void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, Partia
14971534
{
14981535
return;
14991536
}
1500-
entityDecl = DoDecompile(property, decompileRun, decompilationContext.WithCurrentMember(property));
1537+
entityDecl = DoDecompile(property, decompileRun, decompilationContext.WithCurrentMember(property), null);
15011538
entityMap.Add(property, entityDecl);
15021539
break;
15031540
case IMethod method:
15041541
if (recordDecompiler?.MethodIsGenerated(method) == true)
15051542
{
15061543
return;
15071544
}
1508-
entityDecl = DoDecompile(method, decompileRun, decompilationContext.WithCurrentMember(method));
1545+
entityDecl = DoDecompile(method, decompileRun, decompilationContext.WithCurrentMember(method), null);
15091546
entityMap.Add(method, entityDecl);
15101547
foreach (var helper in AddInterfaceImplHelpers(entityDecl, method, typeSystemAstBuilder))
15111548
{
@@ -1543,6 +1580,19 @@ void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, Partia
15431580
}
15441581
}
15451582

1583+
private EntityDeclaration DoDecompileExtensionMember(IMember extMember, ExtensionInfo info, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
1584+
{
1585+
switch (extMember)
1586+
{
1587+
case IProperty p:
1588+
return DoDecompile(p, decompileRun, decompilationContext.WithCurrentMember(p), info);
1589+
case IMethod m:
1590+
return DoDecompile(m, decompileRun, decompilationContext.WithCurrentMember(m), info);
1591+
}
1592+
1593+
throw new NotSupportedException($"Extension member {extMember} is not supported for decompilation.");
1594+
}
1595+
15461596
EnumValueDisplayMode DetectBestEnumValueDisplayMode(ITypeDefinition typeDef, MetadataFile module)
15471597
{
15481598
if (typeDef.HasAttribute(KnownAttribute.Flags))
@@ -1604,7 +1654,7 @@ EnumValueDisplayMode DetectBestEnumValueDisplayMode(ITypeDefinition typeDef, Met
16041654
return firstValue == 0 ? EnumValueDisplayMode.None : EnumValueDisplayMode.FirstOnly;
16051655
}
16061656

1607-
EntityDeclaration DoDecompile(IMethod method, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
1657+
EntityDeclaration DoDecompile(IMethod method, DecompileRun decompileRun, ITypeResolveContext decompilationContext, ExtensionInfo extensionInfo)
16081658
{
16091659
Debug.Assert(decompilationContext.CurrentMember == method);
16101660
var watch = System.Diagnostics.Stopwatch.StartNew();
@@ -1630,7 +1680,7 @@ EntityDeclaration DoDecompile(IMethod method, DecompileRun decompileRun, ITypeRe
16301680
}
16311681
if (methodDefinition.HasBody())
16321682
{
1633-
DecompileBody(method, methodDecl, decompileRun, decompilationContext);
1683+
DecompileBody(method, methodDecl, decompileRun, decompilationContext, extensionInfo);
16341684
}
16351685
else if (!method.IsAbstract && method.DeclaringType.Kind != TypeKind.Interface)
16361686
{
@@ -1699,7 +1749,7 @@ internal static bool IsWindowsFormsInitializeComponentMethod(IMethod method)
16991749
return method.ReturnType.Kind == TypeKind.Void && method.Name == "InitializeComponent" && method.DeclaringTypeDefinition.GetNonInterfaceBaseTypes().Any(t => t.FullName == "System.Windows.Forms.Control");
17001750
}
17011751

1702-
void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
1752+
void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun decompileRun, ITypeResolveContext decompilationContext, ExtensionInfo extensionInfo)
17031753
{
17041754
try
17051755
{
@@ -1708,6 +1758,14 @@ void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun de
17081758
UseRefLocalsForAccurateOrderOfEvaluation = settings.UseRefLocalsForAccurateOrderOfEvaluation,
17091759
DebugInfo = DebugInfoProvider
17101760
};
1761+
int parameterOffset = 0;
1762+
if (extensionInfo != null)
1763+
{
1764+
if (!method.IsStatic)
1765+
parameterOffset = 1; // implementation method has an additional receiver parameter
1766+
method = extensionInfo.InfoOfExtensionMember(method).Value.ImplementationMethod;
1767+
}
1768+
17111769
var methodDef = metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
17121770
var body = BlockStatement.Null;
17131771
MethodBodyBlock methodBody;
@@ -1727,7 +1785,7 @@ void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun de
17271785
var function = ilReader.ReadIL((MethodDefinitionHandle)method.MetadataToken, methodBody, cancellationToken: CancellationToken);
17281786
function.CheckInvariant(ILPhase.Normal);
17291787

1730-
AddAnnotationsToDeclaration(method, entityDecl, function);
1788+
AddAnnotationsToDeclaration(method, entityDecl, function, parameterOffset);
17311789

17321790
var localSettings = settings.Clone();
17331791
if (IsWindowsFormsInitializeComponentMethod(method))
@@ -1786,9 +1844,9 @@ void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun de
17861844
}
17871845
}
17881846

1789-
internal static void AddAnnotationsToDeclaration(IMethod method, EntityDeclaration entityDecl, ILFunction function)
1847+
internal static void AddAnnotationsToDeclaration(IMethod method, EntityDeclaration entityDecl, ILFunction function, int parameterOffset = 0)
17901848
{
1791-
int i = 0;
1849+
int i = parameterOffset;
17921850
var parameters = function.Variables.Where(v => v.Kind == VariableKind.Parameter).ToDictionary(v => v.Index);
17931851
foreach (var parameter in entityDecl.GetChildrenByRole(Roles.Parameter))
17941852
{
@@ -2023,7 +2081,7 @@ internal static bool IsFixedField(IField field, out IType type, out int elementC
20232081
return false;
20242082
}
20252083

2026-
EntityDeclaration DoDecompile(IProperty property, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
2084+
EntityDeclaration DoDecompile(IProperty property, DecompileRun decompileRun, ITypeResolveContext decompilationContext, ExtensionInfo extensionInfo)
20272085
{
20282086
Debug.Assert(decompilationContext.CurrentMember == property);
20292087
var watch = System.Diagnostics.Stopwatch.StartNew();
@@ -2053,11 +2111,11 @@ EntityDeclaration DoDecompile(IProperty property, DecompileRun decompileRun, ITy
20532111
bool setterHasBody = property.CanSet && property.Setter.HasBody;
20542112
if (getterHasBody)
20552113
{
2056-
DecompileBody(property.Getter, getter, decompileRun, decompilationContext);
2114+
DecompileBody(property.Getter, getter, decompileRun, decompilationContext, extensionInfo);
20572115
}
20582116
if (setterHasBody)
20592117
{
2060-
DecompileBody(property.Setter, setter, decompileRun, decompilationContext);
2118+
DecompileBody(property.Setter, setter, decompileRun, decompilationContext, extensionInfo);
20612119
}
20622120
if (!getterHasBody && !setterHasBody && !property.IsAbstract && property.DeclaringType.Kind != TypeKind.Interface)
20632121
{
@@ -2113,11 +2171,11 @@ EntityDeclaration DoDecompile(IEvent ev, DecompileRun decompileRun, ITypeResolve
21132171
}
21142172
if (adderHasBody)
21152173
{
2116-
DecompileBody(ev.AddAccessor, ((CustomEventDeclaration)eventDecl).AddAccessor, decompileRun, decompilationContext);
2174+
DecompileBody(ev.AddAccessor, ((CustomEventDeclaration)eventDecl).AddAccessor, decompileRun, decompilationContext, null);
21172175
}
21182176
if (removerHasBody)
21192177
{
2120-
DecompileBody(ev.RemoveAccessor, ((CustomEventDeclaration)eventDecl).RemoveAccessor, decompileRun, decompilationContext);
2178+
DecompileBody(ev.RemoveAccessor, ((CustomEventDeclaration)eventDecl).RemoveAccessor, decompileRun, decompilationContext, null);
21212179
}
21222180
if (!adderHasBody && !removerHasBody && !ev.IsAbstract && ev.DeclaringType.Kind != TypeKind.Interface)
21232181
{

0 commit comments

Comments
 (0)