Skip to content

Commit b87f012

Browse files
Add support for extensions in CSharpDecompiler
1 parent e66dcfb commit b87f012

File tree

1 file changed

+78
-19
lines changed

1 file changed

+78
-19
lines changed

ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

Lines changed: 78 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,45 @@ 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+
AddAnnotationsToDeclaration(method, ext, function, parameterOffset);
1374+
ext.Constraints.AddRange(group.Key.DeclaringTypeDefinition.TypeParameters.Select(c => typeSystemAstBuilder.ConvertTypeParameterConstraint(c)));
1375+
1376+
foreach (var member in group)
1377+
{
1378+
IMember extMember = member.ExtensionMember;
1379+
if (member.ExtensionMember.IsAccessor)
1380+
{
1381+
extMember = member.ExtensionMember.AccessorOwner;
1382+
}
1383+
if (entityMap.Contains(extMember) || extMember.MetadataToken.IsNil)
1384+
{
1385+
// Member is already decompiled.
1386+
continue;
1387+
}
1388+
EntityDeclaration extMemberDecl = DoDecompileExtensionMember(extMember, typeDef.ExtensionInfo, decompileRun, decompilationContext);
1389+
ext.Members.Add(extMemberDecl);
1390+
entityMap.Add(extMember, extMemberDecl);
1391+
}
1392+
1393+
typeDecl.Members.Add(ext);
1394+
}
1395+
}
1396+
13641397
// Decompile members that are not compiler-generated.
13651398
foreach (var entity in allOrderedEntities)
13661399
{
13671400
if (entity.MetadataToken.IsNil || MemberIsHidden(module.MetadataFile, entity.MetadataToken, settings))
13681401
{
13691402
continue;
13701403
}
1371-
DoDecompileMember(entity, recordDecompiler, partialTypeInfo);
1404+
DoDecompileMember(entity, recordDecompiler, partialTypeInfo, typeDef.ExtensionInfo);
13721405
}
13731406

13741407
// Decompile compiler-generated members that are still needed.
@@ -1380,7 +1413,7 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
13801413
// Member is already decompiled.
13811414
continue;
13821415
}
1383-
DoDecompileMember(entity, recordDecompiler, partialTypeInfo);
1416+
DoDecompileMember(entity, recordDecompiler, partialTypeInfo, typeDef.ExtensionInfo);
13841417
}
13851418

13861419
// Add all decompiled members to syntax tree in the correct order.
@@ -1470,13 +1503,18 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
14701503
Instrumentation.DecompilerEventSource.Log.DoDecompileTypeDefinition(typeDef.FullName, watch.ElapsedMilliseconds);
14711504
}
14721505

1473-
void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, PartialTypeInfo partialType)
1506+
void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, PartialTypeInfo partialType, ExtensionInfo extensionInfo)
14741507
{
14751508
if (partialType != null && partialType.IsDeclaredMember(entity.MetadataToken))
14761509
{
14771510
return;
14781511
}
14791512

1513+
if (settings.ExtensionMembers && extensionInfo != null && entity is IMethod m && extensionInfo.InfoOfImplementationMember(m).HasValue)
1514+
{
1515+
return;
1516+
}
1517+
14801518
EntityDeclaration entityDecl;
14811519
switch (entity)
14821520
{
@@ -1497,15 +1535,15 @@ void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, Partia
14971535
{
14981536
return;
14991537
}
1500-
entityDecl = DoDecompile(property, decompileRun, decompilationContext.WithCurrentMember(property));
1538+
entityDecl = DoDecompile(property, decompileRun, decompilationContext.WithCurrentMember(property), null);
15011539
entityMap.Add(property, entityDecl);
15021540
break;
15031541
case IMethod method:
15041542
if (recordDecompiler?.MethodIsGenerated(method) == true)
15051543
{
15061544
return;
15071545
}
1508-
entityDecl = DoDecompile(method, decompileRun, decompilationContext.WithCurrentMember(method));
1546+
entityDecl = DoDecompile(method, decompileRun, decompilationContext.WithCurrentMember(method), null);
15091547
entityMap.Add(method, entityDecl);
15101548
foreach (var helper in AddInterfaceImplHelpers(entityDecl, method, typeSystemAstBuilder))
15111549
{
@@ -1543,6 +1581,19 @@ void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, Partia
15431581
}
15441582
}
15451583

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

1607-
EntityDeclaration DoDecompile(IMethod method, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
1658+
EntityDeclaration DoDecompile(IMethod method, DecompileRun decompileRun, ITypeResolveContext decompilationContext, ExtensionInfo extensionInfo)
16081659
{
16091660
Debug.Assert(decompilationContext.CurrentMember == method);
16101661
var watch = System.Diagnostics.Stopwatch.StartNew();
@@ -1630,7 +1681,7 @@ EntityDeclaration DoDecompile(IMethod method, DecompileRun decompileRun, ITypeRe
16301681
}
16311682
if (methodDefinition.HasBody())
16321683
{
1633-
DecompileBody(method, methodDecl, decompileRun, decompilationContext);
1684+
DecompileBody(method, methodDecl, decompileRun, decompilationContext, extensionInfo);
16341685
}
16351686
else if (!method.IsAbstract && method.DeclaringType.Kind != TypeKind.Interface)
16361687
{
@@ -1699,7 +1750,7 @@ internal static bool IsWindowsFormsInitializeComponentMethod(IMethod method)
16991750
return method.ReturnType.Kind == TypeKind.Void && method.Name == "InitializeComponent" && method.DeclaringTypeDefinition.GetNonInterfaceBaseTypes().Any(t => t.FullName == "System.Windows.Forms.Control");
17001751
}
17011752

1702-
void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
1753+
void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun decompileRun, ITypeResolveContext decompilationContext, ExtensionInfo extensionInfo)
17031754
{
17041755
try
17051756
{
@@ -1708,6 +1759,14 @@ void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun de
17081759
UseRefLocalsForAccurateOrderOfEvaluation = settings.UseRefLocalsForAccurateOrderOfEvaluation,
17091760
DebugInfo = DebugInfoProvider
17101761
};
1762+
int parameterOffset = 0;
1763+
if (extensionInfo != null)
1764+
{
1765+
if (!method.IsStatic)
1766+
parameterOffset = 1; // implementation method has an additional receiver parameter
1767+
method = extensionInfo.InfoOfExtensionMember(method).Value.ImplementationMethod;
1768+
}
1769+
17111770
var methodDef = metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
17121771
var body = BlockStatement.Null;
17131772
MethodBodyBlock methodBody;
@@ -1727,7 +1786,7 @@ void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun de
17271786
var function = ilReader.ReadIL((MethodDefinitionHandle)method.MetadataToken, methodBody, cancellationToken: CancellationToken);
17281787
function.CheckInvariant(ILPhase.Normal);
17291788

1730-
AddAnnotationsToDeclaration(method, entityDecl, function);
1789+
AddAnnotationsToDeclaration(method, entityDecl, function, parameterOffset);
17311790

17321791
var localSettings = settings.Clone();
17331792
if (IsWindowsFormsInitializeComponentMethod(method))
@@ -1786,9 +1845,9 @@ void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun de
17861845
}
17871846
}
17881847

1789-
internal static void AddAnnotationsToDeclaration(IMethod method, EntityDeclaration entityDecl, ILFunction function)
1848+
internal static void AddAnnotationsToDeclaration(IMethod method, EntityDeclaration entityDecl, ILFunction function, int parameterOffset = 0)
17901849
{
1791-
int i = 0;
1850+
int i = parameterOffset;
17921851
var parameters = function.Variables.Where(v => v.Kind == VariableKind.Parameter).ToDictionary(v => v.Index);
17931852
foreach (var parameter in entityDecl.GetChildrenByRole(Roles.Parameter))
17941853
{
@@ -2023,7 +2082,7 @@ internal static bool IsFixedField(IField field, out IType type, out int elementC
20232082
return false;
20242083
}
20252084

2026-
EntityDeclaration DoDecompile(IProperty property, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
2085+
EntityDeclaration DoDecompile(IProperty property, DecompileRun decompileRun, ITypeResolveContext decompilationContext, ExtensionInfo extensionInfo)
20272086
{
20282087
Debug.Assert(decompilationContext.CurrentMember == property);
20292088
var watch = System.Diagnostics.Stopwatch.StartNew();
@@ -2053,11 +2112,11 @@ EntityDeclaration DoDecompile(IProperty property, DecompileRun decompileRun, ITy
20532112
bool setterHasBody = property.CanSet && property.Setter.HasBody;
20542113
if (getterHasBody)
20552114
{
2056-
DecompileBody(property.Getter, getter, decompileRun, decompilationContext);
2115+
DecompileBody(property.Getter, getter, decompileRun, decompilationContext, extensionInfo);
20572116
}
20582117
if (setterHasBody)
20592118
{
2060-
DecompileBody(property.Setter, setter, decompileRun, decompilationContext);
2119+
DecompileBody(property.Setter, setter, decompileRun, decompilationContext, extensionInfo);
20612120
}
20622121
if (!getterHasBody && !setterHasBody && !property.IsAbstract && property.DeclaringType.Kind != TypeKind.Interface)
20632122
{
@@ -2113,11 +2172,11 @@ EntityDeclaration DoDecompile(IEvent ev, DecompileRun decompileRun, ITypeResolve
21132172
}
21142173
if (adderHasBody)
21152174
{
2116-
DecompileBody(ev.AddAccessor, ((CustomEventDeclaration)eventDecl).AddAccessor, decompileRun, decompilationContext);
2175+
DecompileBody(ev.AddAccessor, ((CustomEventDeclaration)eventDecl).AddAccessor, decompileRun, decompilationContext, null);
21172176
}
21182177
if (removerHasBody)
21192178
{
2120-
DecompileBody(ev.RemoveAccessor, ((CustomEventDeclaration)eventDecl).RemoveAccessor, decompileRun, decompilationContext);
2179+
DecompileBody(ev.RemoveAccessor, ((CustomEventDeclaration)eventDecl).RemoveAccessor, decompileRun, decompilationContext, null);
21212180
}
21222181
if (!adderHasBody && !removerHasBody && !ev.IsAbstract && ev.DeclaringType.Kind != TypeKind.Interface)
21232182
{

0 commit comments

Comments
 (0)