diff --git a/ILSpy.BamlDecompiler/BamlConnectionId.cs b/ILSpy.BamlDecompiler/BamlConnectionId.cs index 1e4bf67e7..9bf19607d 100644 --- a/ILSpy.BamlDecompiler/BamlConnectionId.cs +++ b/ILSpy.BamlDecompiler/BamlConnectionId.cs @@ -22,6 +22,14 @@ namespace ILSpy.BamlDecompiler { + /// + /// Represents a field assignment of a XAML code-behind class. + /// + internal sealed class FieldAssignment + { + public string FieldName; + } + /// /// Represents an event registration of a XAML code-behind class. /// diff --git a/ILSpy.BamlDecompiler/Handlers/Records/OptimizedStaticResourceHandler.cs b/ILSpy.BamlDecompiler/Handlers/Records/OptimizedStaticResourceHandler.cs index 85b275966..53b5a773e 100644 --- a/ILSpy.BamlDecompiler/Handlers/Records/OptimizedStaticResourceHandler.cs +++ b/ILSpy.BamlDecompiler/Handlers/Records/OptimizedStaticResourceHandler.cs @@ -81,7 +81,7 @@ namespace ILSpy.BamlDecompiler.Handlers name = res.Item1 + "." + res.Item2; else name = res.Item1 + "." + res.Item3; - var xmlns = ctx.GetXmlNamespace("http://schemas.microsoft.com/winfx/2006/xaml/presentation"); + var xmlns = ctx.GetXmlNamespace(XamlContext.KnownNamespace_Presentation); attrName = ctx.ToString(parent.Xaml, xmlns.GetName(name)); } else diff --git a/ILSpy.BamlDecompiler/Handlers/Records/PropertyWithExtensionHandler.cs b/ILSpy.BamlDecompiler/Handlers/Records/PropertyWithExtensionHandler.cs index c7fe61ca5..35c0a76fd 100644 --- a/ILSpy.BamlDecompiler/Handlers/Records/PropertyWithExtensionHandler.cs +++ b/ILSpy.BamlDecompiler/Handlers/Records/PropertyWithExtensionHandler.cs @@ -85,7 +85,7 @@ namespace ILSpy.BamlDecompiler.Handlers name = res.Item1 + "." + res.Item2; else name = res.Item1 + "." + res.Item3; - var xmlns = ctx.GetXmlNamespace("http://schemas.microsoft.com/winfx/2006/xaml/presentation"); + var xmlns = ctx.GetXmlNamespace(XamlContext.KnownNamespace_Presentation); attrName = ctx.ToString(parent.Xaml, xmlns.GetName(name)); } else diff --git a/ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs b/ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs index 7d4bd1e83..fe22c32ab 100644 --- a/ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs +++ b/ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs @@ -41,20 +41,29 @@ namespace ILSpy.BamlDecompiler.Rewrite public void Run(XamlContext ctx, XDocument document) { - var mappings = DecompileEventMappings(ctx, document); - ProcessConnectionIds(document.Root, mappings); + var connections = DecompileConnections(ctx, document); + ProcessConnectionIds(ctx, document.Root, connections); } - static void ProcessConnectionIds(XElement element, - List<(LongSet key, EventRegistration[] value)> eventMappings) + static void ProcessConnectionIds(XamlContext ctx, XElement element, + (List<(LongSet key, FieldAssignment value)> fieldAssignments, + List<(LongSet key, EventRegistration[] value)> eventMappings) connections) { foreach (var child in element.Elements()) - ProcessConnectionIds(child, eventMappings); + ProcessConnectionIds(ctx, child, connections); + var fieldAssignments = connections.fieldAssignments; + var eventMappings = connections.eventMappings; foreach (var annotation in element.Annotations()) { int index; - if ((index = eventMappings.FindIndex(item => item.key.Contains(annotation.Id))) > -1) + if ((index = fieldAssignments.FindIndex(item => item.key.Contains(annotation.Id))) > -1) + { + var xName = ctx.GetKnownNamespace("Name", XamlContext.KnownNamespace_Xaml, element); + if (element.Attribute("Name") is null && element.Attribute(xName) is null) + element.Add(new XAttribute(xName, fieldAssignments[index].value.FieldName)); + } + else if ((index = eventMappings.FindIndex(item => item.key.Contains(annotation.Id))) > -1) { foreach (var entry in eventMappings[index].value) { @@ -79,28 +88,30 @@ namespace ILSpy.BamlDecompiler.Rewrite } } - List<(LongSet, EventRegistration[])> DecompileEventMappings(XamlContext ctx, XDocument document) + (List<(LongSet, FieldAssignment)>, List<(LongSet, EventRegistration[])>) DecompileConnections + (XamlContext ctx, XDocument document) { - var result = new List<(LongSet, EventRegistration[])>(); + var fieldAssignments = new List<(LongSet key, FieldAssignment value)>(); + var eventMappings = new List<(LongSet, EventRegistration[])>(); var xClass = document.Root .Elements().First() .Attribute(ctx.GetKnownNamespace("Class", XamlContext.KnownNamespace_Xaml)); if (xClass == null) - return result; + return (fieldAssignments, eventMappings); var type = ctx.TypeSystem.FindType(new FullTypeName(xClass.Value)).GetDefinition(); if (type == null) - return result; + return (fieldAssignments, eventMappings); - DecompileEventMappings(ctx, result, componentConnectorTypeName, type); - DecompileEventMappings(ctx, result, styleConnectorTypeName, type); + DecompileConnections(ctx, fieldAssignments, eventMappings, componentConnectorTypeName, type); + DecompileConnections(ctx, fieldAssignments, eventMappings, styleConnectorTypeName, type); - return result; + return (fieldAssignments, eventMappings); } - void DecompileEventMappings(XamlContext ctx, List<(LongSet, EventRegistration[])> result, - FullTypeName connectorTypeName, ITypeDefinition type) + void DecompileConnections(XamlContext ctx, List<(LongSet, FieldAssignment)> fieldAssignments, + List<(LongSet, EventRegistration[])> eventMappings, FullTypeName connectorTypeName, ITypeDefinition type) { var connectorInterface = ctx.TypeSystem.FindType(connectorTypeName).GetDefinition(); if (connectorInterface == null) @@ -148,11 +159,19 @@ namespace ILSpy.BamlDecompiler.Rewrite { foreach (var section in ilSwitch.Sections) { - events.Clear(); - FindEvents(section.Body, events); - if (events.Count > 0) + var field = FindField(section.Body); + if (!(field is null)) { - result.Add((section.Labels, events.ToArray())); + fieldAssignments.Add((section.Labels, field)); + } + else + { + events.Clear(); + FindEvents(section.Body, events); + if (events.Count > 0) + { + eventMappings.Add((section.Labels, events.ToArray())); + } } } } @@ -169,16 +188,54 @@ namespace ILSpy.BamlDecompiler.Rewrite var inst = comp.Kind == ComparisonKind.Inequality ? ifInst.FalseInst : ifInst.TrueInst; - events.Clear(); - FindEvents(inst, events); - if (events.Count > 0) + + var field = FindField(inst); + if (!(field is null)) { - result.Add((new LongSet(id), events.ToArray())); + fieldAssignments.Add((new LongSet(id), field)); + } + else + { + events.Clear(); + FindEvents(inst, events); + if (events.Count > 0) + { + eventMappings.Add((new LongSet(id), events.ToArray())); + } } } } } + FieldAssignment FindField(ILInstruction inst) + { + switch (inst) + { + case Block b: + var t = b.Instructions.FirstOrDefault(); + if (!(t is null) && MatchFieldAssignment(t, out var field)) + return field; + return null; + case Branch br: + return FindField(br.TargetBlock); + default: + if (MatchFieldAssignment(inst, out field)) + return field; + return null; + } + } + + bool MatchFieldAssignment(ILInstruction inst, out FieldAssignment field) + { + field = null; + if (!inst.MatchStFld(out _, out var fld, out var value) || !value.MatchCastClass(out var arg, out _) + || !(arg.MatchLdLoc(out var t) && t.Kind == VariableKind.Parameter && t.Index == 1)) + return false; + + field = new FieldAssignment { FieldName = fld.Name }; + return true; + } + void FindEvents(ILInstruction inst, List events) { EventRegistration @event;