Browse Source

Add support for extensions in CSharpDecompiler

pull/3530/head
Siegfried Pammer 5 months ago
parent
commit
f8dcd95b31
  1. 96
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

96
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -318,7 +318,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -318,7 +318,9 @@ namespace ICSharpCode.Decompiler.CSharp
return true;
if (settings.FixedBuffers && name.StartsWith("<", StringComparison.Ordinal) && name.Contains("__FixedBuffer"))
return true;
if (settings.InlineArrays && name.StartsWith("<>y__InlineArray", StringComparison.Ordinal) && name.EndsWith("`1"))
if (settings.InlineArrays && name.StartsWith("<>y__InlineArray", StringComparison.Ordinal) && name.EndsWith("`1", StringComparison.Ordinal))
return true;
if (settings.ExtensionMembers && name.StartsWith("<>E__", StringComparison.Ordinal))
return true;
}
else if (type.IsCompilerGenerated(metadata))
@ -1037,7 +1039,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1037,7 +1039,7 @@ namespace ICSharpCode.Decompiler.CSharp
break;
case HandleKind.MethodDefinition:
IMethod method = module.GetDefinition((MethodDefinitionHandle)entity);
syntaxTree.Members.Add(DoDecompile(method, decompileRun, new SimpleTypeResolveContext(method)));
syntaxTree.Members.Add(DoDecompile(method, decompileRun, new SimpleTypeResolveContext(method), null));
if (first)
{
parentTypeDef = method.DeclaringTypeDefinition;
@ -1054,7 +1056,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1054,7 +1056,7 @@ namespace ICSharpCode.Decompiler.CSharp
break;
case HandleKind.PropertyDefinition:
IProperty property = module.GetDefinition((PropertyDefinitionHandle)entity);
syntaxTree.Members.Add(DoDecompile(property, decompileRun, new SimpleTypeResolveContext(property)));
syntaxTree.Members.Add(DoDecompile(property, decompileRun, new SimpleTypeResolveContext(property), null));
if (first)
{
parentTypeDef = property.DeclaringTypeDefinition;
@ -1361,6 +1363,36 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1361,6 +1363,36 @@ namespace ICSharpCode.Decompiler.CSharp
partialTypeInfo = null;
}
if (settings.ExtensionMembers)
{
foreach (var group in typeDef.ExtensionInfo?.GetGroups() ?? [])
{
var ext = new ExtensionDeclaration();
ext.TypeParameters.AddRange(group.Key.DeclaringTypeDefinition.TypeParameters.Select(tp => typeSystemAstBuilder.ConvertTypeParameter(tp)));
ext.ReceiverParameters.Add(typeSystemAstBuilder.ConvertParameter(group.Key.Parameters.Single()));
ext.Constraints.AddRange(group.Key.DeclaringTypeDefinition.TypeParameters.Select(c => typeSystemAstBuilder.ConvertTypeParameterConstraint(c)));
foreach (var member in group)
{
IMember extMember = member.ExtensionMember;
if (member.ExtensionMember.IsAccessor)
{
extMember = member.ExtensionMember.AccessorOwner;
}
if (entityMap.Contains(extMember) || extMember.MetadataToken.IsNil)
{
// Member is already decompiled.
continue;
}
EntityDeclaration extMemberDecl = DoDecompileExtensionMember(extMember, typeDef.ExtensionInfo, decompileRun, decompilationContext);
ext.Members.Add(extMemberDecl);
entityMap.Add(extMember, extMemberDecl);
}
typeDecl.Members.Add(ext);
}
}
// Decompile members that are not compiler-generated.
foreach (var entity in allOrderedEntities)
{
@ -1368,7 +1400,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1368,7 +1400,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
continue;
}
DoDecompileMember(entity, recordDecompiler, partialTypeInfo);
DoDecompileMember(entity, recordDecompiler, partialTypeInfo, typeDef.ExtensionInfo);
}
// Decompile compiler-generated members that are still needed.
@ -1380,7 +1412,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1380,7 +1412,7 @@ namespace ICSharpCode.Decompiler.CSharp
// Member is already decompiled.
continue;
}
DoDecompileMember(entity, recordDecompiler, partialTypeInfo);
DoDecompileMember(entity, recordDecompiler, partialTypeInfo, typeDef.ExtensionInfo);
}
// Add all decompiled members to syntax tree in the correct order.
@ -1470,13 +1502,18 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1470,13 +1502,18 @@ namespace ICSharpCode.Decompiler.CSharp
Instrumentation.DecompilerEventSource.Log.DoDecompileTypeDefinition(typeDef.FullName, watch.ElapsedMilliseconds);
}
void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, PartialTypeInfo partialType)
void DoDecompileMember(IEntity entity, RecordDecompiler recordDecompiler, PartialTypeInfo partialType, ExtensionInfo extensionInfo)
{
if (partialType != null && partialType.IsDeclaredMember(entity.MetadataToken))
{
return;
}
if (settings.ExtensionMembers && extensionInfo != null && entity is IMethod m && extensionInfo.InfoOfImplementationMember(m).HasValue)
{
return;
}
EntityDeclaration entityDecl;
switch (entity)
{
@ -1497,7 +1534,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1497,7 +1534,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
return;
}
entityDecl = DoDecompile(property, decompileRun, decompilationContext.WithCurrentMember(property));
entityDecl = DoDecompile(property, decompileRun, decompilationContext.WithCurrentMember(property), null);
entityMap.Add(property, entityDecl);
break;
case IMethod method:
@ -1505,7 +1542,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1505,7 +1542,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
return;
}
entityDecl = DoDecompile(method, decompileRun, decompilationContext.WithCurrentMember(method));
entityDecl = DoDecompile(method, decompileRun, decompilationContext.WithCurrentMember(method), null);
entityMap.Add(method, entityDecl);
foreach (var helper in AddInterfaceImplHelpers(entityDecl, method, typeSystemAstBuilder))
{
@ -1543,6 +1580,19 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1543,6 +1580,19 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
private EntityDeclaration DoDecompileExtensionMember(IMember extMember, ExtensionInfo info, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
{
switch (extMember)
{
case IProperty p:
return DoDecompile(p, decompileRun, decompilationContext.WithCurrentMember(p), info);
case IMethod m:
return DoDecompile(m, decompileRun, decompilationContext.WithCurrentMember(m), info);
}
throw new NotSupportedException($"Extension member {extMember} is not supported for decompilation.");
}
EnumValueDisplayMode DetectBestEnumValueDisplayMode(ITypeDefinition typeDef, MetadataFile module)
{
if (typeDef.HasAttribute(KnownAttribute.Flags))
@ -1604,7 +1654,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1604,7 +1654,7 @@ namespace ICSharpCode.Decompiler.CSharp
return firstValue == 0 ? EnumValueDisplayMode.None : EnumValueDisplayMode.FirstOnly;
}
EntityDeclaration DoDecompile(IMethod method, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
EntityDeclaration DoDecompile(IMethod method, DecompileRun decompileRun, ITypeResolveContext decompilationContext, ExtensionInfo extensionInfo)
{
Debug.Assert(decompilationContext.CurrentMember == method);
var watch = System.Diagnostics.Stopwatch.StartNew();
@ -1630,7 +1680,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1630,7 +1680,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
if (methodDefinition.HasBody())
{
DecompileBody(method, methodDecl, decompileRun, decompilationContext);
DecompileBody(method, methodDecl, decompileRun, decompilationContext, extensionInfo);
}
else if (!method.IsAbstract && method.DeclaringType.Kind != TypeKind.Interface)
{
@ -1699,7 +1749,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1699,7 +1749,7 @@ namespace ICSharpCode.Decompiler.CSharp
return method.ReturnType.Kind == TypeKind.Void && method.Name == "InitializeComponent" && method.DeclaringTypeDefinition.GetNonInterfaceBaseTypes().Any(t => t.FullName == "System.Windows.Forms.Control");
}
void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
void DecompileBody(IMethod method, EntityDeclaration entityDecl, DecompileRun decompileRun, ITypeResolveContext decompilationContext, ExtensionInfo extensionInfo)
{
try
{
@ -1708,6 +1758,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1708,6 +1758,14 @@ namespace ICSharpCode.Decompiler.CSharp
UseRefLocalsForAccurateOrderOfEvaluation = settings.UseRefLocalsForAccurateOrderOfEvaluation,
DebugInfo = DebugInfoProvider
};
int parameterOffset = 0;
if (extensionInfo != null)
{
if (!method.IsStatic)
parameterOffset = 1; // implementation method has an additional receiver parameter
method = extensionInfo.InfoOfExtensionMember(method).Value.ImplementationMethod;
}
var methodDef = metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
var body = BlockStatement.Null;
MethodBodyBlock methodBody;
@ -1727,7 +1785,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1727,7 +1785,7 @@ namespace ICSharpCode.Decompiler.CSharp
var function = ilReader.ReadIL((MethodDefinitionHandle)method.MetadataToken, methodBody, cancellationToken: CancellationToken);
function.CheckInvariant(ILPhase.Normal);
AddAnnotationsToDeclaration(method, entityDecl, function);
AddAnnotationsToDeclaration(method, entityDecl, function, parameterOffset);
var localSettings = settings.Clone();
if (IsWindowsFormsInitializeComponentMethod(method))
@ -1786,9 +1844,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1786,9 +1844,9 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
internal static void AddAnnotationsToDeclaration(IMethod method, EntityDeclaration entityDecl, ILFunction function)
internal static void AddAnnotationsToDeclaration(IMethod method, EntityDeclaration entityDecl, ILFunction function, int parameterOffset = 0)
{
int i = 0;
int i = parameterOffset;
var parameters = function.Variables.Where(v => v.Kind == VariableKind.Parameter).ToDictionary(v => v.Index);
foreach (var parameter in entityDecl.GetChildrenByRole(Roles.Parameter))
{
@ -2023,7 +2081,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2023,7 +2081,7 @@ namespace ICSharpCode.Decompiler.CSharp
return false;
}
EntityDeclaration DoDecompile(IProperty property, DecompileRun decompileRun, ITypeResolveContext decompilationContext)
EntityDeclaration DoDecompile(IProperty property, DecompileRun decompileRun, ITypeResolveContext decompilationContext, ExtensionInfo extensionInfo)
{
Debug.Assert(decompilationContext.CurrentMember == property);
var watch = System.Diagnostics.Stopwatch.StartNew();
@ -2053,11 +2111,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2053,11 +2111,11 @@ namespace ICSharpCode.Decompiler.CSharp
bool setterHasBody = property.CanSet && property.Setter.HasBody;
if (getterHasBody)
{
DecompileBody(property.Getter, getter, decompileRun, decompilationContext);
DecompileBody(property.Getter, getter, decompileRun, decompilationContext, extensionInfo);
}
if (setterHasBody)
{
DecompileBody(property.Setter, setter, decompileRun, decompilationContext);
DecompileBody(property.Setter, setter, decompileRun, decompilationContext, extensionInfo);
}
if (!getterHasBody && !setterHasBody && !property.IsAbstract && property.DeclaringType.Kind != TypeKind.Interface)
{
@ -2113,11 +2171,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2113,11 +2171,11 @@ namespace ICSharpCode.Decompiler.CSharp
}
if (adderHasBody)
{
DecompileBody(ev.AddAccessor, ((CustomEventDeclaration)eventDecl).AddAccessor, decompileRun, decompilationContext);
DecompileBody(ev.AddAccessor, ((CustomEventDeclaration)eventDecl).AddAccessor, decompileRun, decompilationContext, null);
}
if (removerHasBody)
{
DecompileBody(ev.RemoveAccessor, ((CustomEventDeclaration)eventDecl).RemoveAccessor, decompileRun, decompilationContext);
DecompileBody(ev.RemoveAccessor, ((CustomEventDeclaration)eventDecl).RemoveAccessor, decompileRun, decompilationContext, null);
}
if (!adderHasBody && !removerHasBody && !ev.IsAbstract && ev.DeclaringType.Kind != TypeKind.Interface)
{

Loading…
Cancel
Save