Browse Source

Merge pull request #2281 from wwh1004/fix2

Fix baml decompiler can't find EventSetter
pull/2309/head
Siegfried Pammer 5 years ago committed by GitHub
parent
commit
d055dc784b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      ILSpy.BamlDecompiler/BamlConnectionId.cs
  2. 2
      ILSpy.BamlDecompiler/Handlers/Records/OptimizedStaticResourceHandler.cs
  3. 2
      ILSpy.BamlDecompiler/Handlers/Records/PropertyWithExtensionHandler.cs
  4. 135
      ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs

8
ILSpy.BamlDecompiler/BamlConnectionId.cs

@ -22,6 +22,14 @@ @@ -22,6 +22,14 @@
namespace ILSpy.BamlDecompiler
{
/// <summary>
/// Represents a field assignment of a XAML code-behind class.
/// </summary>
internal sealed class FieldAssignment
{
public string FieldName;
}
/// <summary>
/// Represents an event registration of a XAML code-behind class.
/// </summary>

2
ILSpy.BamlDecompiler/Handlers/Records/OptimizedStaticResourceHandler.cs

@ -81,7 +81,7 @@ namespace ILSpy.BamlDecompiler.Handlers @@ -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

2
ILSpy.BamlDecompiler/Handlers/Records/PropertyWithExtensionHandler.cs

@ -85,7 +85,7 @@ namespace ILSpy.BamlDecompiler.Handlers @@ -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

135
ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs

@ -41,20 +41,29 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -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<BamlConnectionId>())
{
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)
{
@ -72,31 +81,37 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -72,31 +81,37 @@ namespace ILSpy.BamlDecompiler.Rewrite
}
}
}
else
{
element.Add(new XComment($"Unknown connection ID: {annotation.Id}"));
}
}
}
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)
@ -144,11 +159,19 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -144,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()));
}
}
}
}
@ -165,25 +188,66 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -165,25 +188,66 @@ 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<EventRegistration> events)
{
EventRegistration @event;
switch (inst)
{
case Block b:
if (MatchEventSetterCreation(b, out var @event))
for (int i = 0; i < b.Instructions.Count;)
{
events.Add(@event);
break;
if (MatchEventSetterCreation(b, ref i, out @event))
events.Add(@event);
else
i++;
}
foreach (var node in b.Instructions)
{
@ -205,15 +269,17 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -205,15 +269,17 @@ namespace ILSpy.BamlDecompiler.Rewrite
// callvirt set_Event(ldloc v, ldsfld eventName)
// callvirt set_Handler(ldloc v, newobj RoutedEventHandler..ctor(ldloc this, ldftn eventHandler))
// callvirt Add(callvirt get_Setters(castclass System.Windows.Style(ldloc target)), ldloc v)
// leave IL_0007 (nop)
bool MatchEventSetterCreation(Block b, out EventRegistration @event)
bool MatchEventSetterCreation(Block b, ref int pos, out EventRegistration @event)
{
@event = null;
var instr = b.Instructions;
if (instr.Count != 5 || !b.FinalInstruction.MatchNop())
if (!b.FinalInstruction.MatchNop())
{
pos = b.Instructions.Count;
return false;
}
var instr = b.Instructions;
// stloc v(newobj EventSetter..ctor())
if (!instr.ElementAt(0).MatchStLoc(out var v, out var initializer))
if (!instr[pos + 0].MatchStLoc(out var v, out var initializer))
return false;
if (!(initializer is NewObj newObj
&& newObj.Method.DeclaringType.FullName == "System.Windows.EventSetter"
@ -222,7 +288,7 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -222,7 +288,7 @@ namespace ILSpy.BamlDecompiler.Rewrite
return false;
}
//callvirt set_Event(ldloc v, ldsfld eventName)
if (!(instr.ElementAt(1) is CallVirt setEventCall && setEventCall.Arguments.Count == 2))
if (!(instr[pos + 1] is CallVirt setEventCall && setEventCall.Arguments.Count == 2))
return false;
if (!setEventCall.Method.IsAccessor)
return false;
@ -238,7 +304,7 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -238,7 +304,7 @@ namespace ILSpy.BamlDecompiler.Rewrite
eventName = eventName.Remove(eventName.Length - "Event".Length);
}
// callvirt set_Handler(ldloc v, newobj RoutedEventHandler..ctor(ldloc this, ldftn eventHandler))
if (!(instr.ElementAt(2) is CallVirt setHandlerCall && setHandlerCall.Arguments.Count == 2))
if (!(instr[pos + 2] is CallVirt setHandlerCall && setHandlerCall.Arguments.Count == 2))
return false;
if (!setHandlerCall.Method.IsAccessor)
return false;
@ -250,7 +316,7 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -250,7 +316,7 @@ namespace ILSpy.BamlDecompiler.Rewrite
return false;
@event = new EventRegistration { EventName = eventName, MethodName = handlerName };
// callvirt Add(callvirt get_Setters(castclass System.Windows.Style(ldloc target)), ldloc v)
if (!(instr.ElementAt(3) is CallVirt addCall && addCall.Arguments.Count == 2))
if (!(instr[pos + 3] is CallVirt addCall && addCall.Arguments.Count == 2))
return false;
if (addCall.Method.Name != "Add")
return false;
@ -268,6 +334,7 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -268,6 +334,7 @@ namespace ILSpy.BamlDecompiler.Rewrite
return false;
if (!addCall.Arguments[1].MatchLdLoc(v))
return false;
pos += 4;
return true;
}

Loading…
Cancel
Save