Browse Source

Fix #2109: Add support for IStyleConnector.Connect in BAML decompilation

pull/2145/head
Siegfried Pammer 5 years ago
parent
commit
9465054a70
  1. 53
      ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs

53
ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs

@ -34,7 +34,10 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -34,7 +34,10 @@ namespace ILSpy.BamlDecompiler.Rewrite
{
internal class ConnectionIdRewritePass : IRewritePass
{
static readonly TopLevelTypeName componentConnectorTypeName = new TopLevelTypeName("System.Windows.Markup", "IComponentConnector");
static readonly TopLevelTypeName componentConnectorTypeName
= new TopLevelTypeName("System.Windows.Markup", "IComponentConnector");
static readonly TopLevelTypeName styleConnectorTypeName
= new TopLevelTypeName("System.Windows.Markup", "IStyleConnector");
public void Run(XamlContext ctx, XDocument document)
{
@ -42,7 +45,8 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -42,7 +45,8 @@ namespace ILSpy.BamlDecompiler.Rewrite
ProcessConnectionIds(document.Root, mappings);
}
static void ProcessConnectionIds(XElement element, List<(LongSet key, EventRegistration[] value)> eventMappings)
static void ProcessConnectionIds(XElement element,
List<(LongSet key, EventRegistration[] value)> eventMappings)
{
foreach (var child in element.Elements())
ProcessConnectionIds(child, eventMappings);
@ -65,7 +69,9 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -65,7 +69,9 @@ namespace ILSpy.BamlDecompiler.Rewrite
{
var result = new List<(LongSet, EventRegistration[])>();
var xClass = document.Root.Elements().First().Attribute(ctx.GetKnownNamespace("Class", XamlContext.KnownNamespace_Xaml));
var xClass = document.Root
.Elements().First()
.Attribute(ctx.GetKnownNamespace("Class", XamlContext.KnownNamespace_Xaml));
if (xClass == null)
return result;
@ -73,9 +79,18 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -73,9 +79,18 @@ namespace ILSpy.BamlDecompiler.Rewrite
if (type == null)
return result;
var connectorInterface = ctx.TypeSystem.FindType(componentConnectorTypeName).GetDefinition();
DecompileEventMappings(ctx, result, componentConnectorTypeName, type);
DecompileEventMappings(ctx, result, styleConnectorTypeName, type);
return result;
}
void DecompileEventMappings(XamlContext ctx, List<(LongSet, EventRegistration[])> result,
FullTypeName connectorTypeName, ITypeDefinition type)
{
var connectorInterface = ctx.TypeSystem.FindType(connectorTypeName).GetDefinition();
if (connectorInterface == null)
return result;
return;
var connect = connectorInterface.GetMethods(m => m.Name == "Connect").SingleOrDefault();
IMethod method = null;
@ -87,13 +102,14 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -87,13 +102,14 @@ namespace ILSpy.BamlDecompiler.Rewrite
if (m.ExplicitlyImplementedInterfaceMembers.Any(md => md.MemberDefinition.Equals(connect)))
{
method = m;
metadataEntry = module.Metadata.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
metadataEntry = module.Metadata
.GetMethodDefinition((MethodDefinitionHandle)method.MetadataToken);
break;
}
}
if (method == null || metadataEntry.RelativeVirtualAddress <= 0)
return result;
return;
var body = module.Reader.GetMethodBody(metadataEntry.RelativeVirtualAddress);
var genericContext = new GenericContext(
@ -102,7 +118,8 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -102,7 +118,8 @@ namespace ILSpy.BamlDecompiler.Rewrite
// decompile method and optimize the switch
var ilReader = new ILReader(ctx.TypeSystem.MainModule);
var function = ilReader.ReadIL((MethodDefinitionHandle)method.MetadataToken, body, genericContext, ILFunctionKind.TopLevelFunction, ctx.CancellationToken);
var function = ilReader.ReadIL((MethodDefinitionHandle)method.MetadataToken, body, genericContext,
ILFunctionKind.TopLevelFunction, ctx.CancellationToken);
var context = new ILTransformContext(function, ctx.TypeSystem, null) {
CancellationToken = ctx.CancellationToken
@ -130,11 +147,12 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -130,11 +147,12 @@ namespace ILSpy.BamlDecompiler.Rewrite
continue;
if (!comp.Right.MatchLdcI4(out int id))
continue;
var events = FindEvents(comp.Kind == ComparisonKind.Inequality ? ifInst.FalseInst : ifInst.TrueInst);
var events = FindEvents(comp.Kind == ComparisonKind.Inequality
? ifInst.FalseInst
: ifInst.TrueInst);
result.Add((new LongSet(id), events));
}
}
return result;
}
EventRegistration[] FindEvents(ILInstruction inst)
@ -165,8 +183,11 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -165,8 +183,11 @@ namespace ILSpy.BamlDecompiler.Rewrite
if (call == null || call.OpCode == OpCode.NewObj)
return;
if (IsAddEvent(call, out string eventName, out string handlerName) || IsAddAttachedEvent(call, out eventName, out handlerName))
if (IsAddEvent(call, out string eventName, out string handlerName)
|| IsAddAttachedEvent(call, out eventName, out handlerName))
{
events.Add(new EventRegistration { EventName = eventName, MethodName = handlerName });
}
}
bool IsAddAttachedEvent(CallInstruction call, out string eventName, out string handlerName)
@ -182,8 +203,11 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -182,8 +203,11 @@ namespace ILSpy.BamlDecompiler.Rewrite
if (!call.Arguments[1].MatchLdsFld(out IField field))
return false;
eventName = field.DeclaringType.Name + "." + field.Name;
if (eventName.EndsWith("Event", StringComparison.Ordinal) && eventName.Length > "Event".Length)
if (eventName.EndsWith("Event", StringComparison.Ordinal)
&& eventName.Length > "Event".Length)
{
eventName = eventName.Remove(eventName.Length - "Event".Length);
}
var newObj = call.Arguments[2] as NewObj;
if (newObj == null || newObj.Arguments.Count != 2)
return false;
@ -205,8 +229,11 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -205,8 +229,11 @@ namespace ILSpy.BamlDecompiler.Rewrite
if (call.Arguments.Count == 2)
{
var addMethod = call.Method;
if (!addMethod.Name.StartsWith("add_", StringComparison.Ordinal) || addMethod.Parameters.Count != 1)
if (!addMethod.Name.StartsWith("add_", StringComparison.Ordinal)
|| addMethod.Parameters.Count != 1)
{
return false;
}
eventName = addMethod.Name.Substring("add_".Length);
var newObj = call.Arguments[1] as NewObj;
if (newObj == null || newObj.Arguments.Count != 2)

Loading…
Cancel
Save