Browse Source

Fix #2106: EventSetter is lost.

pull/2145/head
Siegfried Pammer 5 years ago
parent
commit
e53fe4fe68
  1. 168
      ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs

168
ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs

@ -59,7 +59,17 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -59,7 +59,17 @@ namespace ILSpy.BamlDecompiler.Rewrite
foreach (var entry in eventMappings[index].value)
{
string xmlns = ""; // TODO : implement xmlns resolver!
element.Add(new XAttribute(xmlns + entry.EventName, entry.MethodName));
var type = element.Annotation<XamlType>();
if (type?.TypeNamespace + "." + type?.TypeName == "System.Windows.Style")
{
element.Add(new XElement(type.Namespace + "EventSetter",
new XAttribute("Event", entry.EventName),
new XAttribute("Handler", entry.MethodName)));
}
else
{
element.Add(new XAttribute(xmlns + entry.EventName, entry.MethodName));
}
}
}
}
@ -133,8 +143,9 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -133,8 +143,9 @@ namespace ILSpy.BamlDecompiler.Rewrite
{
foreach (var section in ilSwitch.Sections)
{
var events = FindEvents(section.Body);
result.Add((section.Labels, events));
var events = new List<EventRegistration>();
FindEvents(section.Body, events);
result.Add((section.Labels, events.ToArray()));
}
}
else
@ -147,47 +158,126 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -147,47 +158,126 @@ namespace ILSpy.BamlDecompiler.Rewrite
continue;
if (!comp.Right.MatchLdcI4(out int id))
continue;
var events = FindEvents(comp.Kind == ComparisonKind.Inequality
var inst = comp.Kind == ComparisonKind.Inequality
? ifInst.FalseInst
: ifInst.TrueInst);
result.Add((new LongSet(id), events));
: ifInst.TrueInst;
var events = new List<EventRegistration>();
FindEvents(inst, events);
result.Add((new LongSet(id), events.ToArray()));
}
}
}
EventRegistration[] FindEvents(ILInstruction inst)
void FindEvents(ILInstruction inst, List<EventRegistration> events)
{
var events = new List<EventRegistration>();
switch (inst)
{
case Block _:
foreach (var node in ((Block)inst).Instructions)
case Block b:
if (MatchEventSetterCreation(b, out var @event))
{
FindEvents(node, events);
events.Add(@event);
break;
}
foreach (var node in b.Instructions)
{
if (MatchSimpleEventRegistration(node, out @event))
events.Add(@event);
}
FindEvents(((Block)inst).FinalInstruction, events);
break;
case Branch br:
return FindEvents(br.TargetBlock);
FindEvents(br.TargetBlock, events);
break;
default:
FindEvents(inst, events);
if (MatchSimpleEventRegistration(inst, out @event))
events.Add(@event);
break;
}
return events.ToArray();
}
void FindEvents(ILInstruction inst, List<EventRegistration> events)
// stloc v(newobj EventSetter..ctor())
// 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)
{
CallInstruction call = inst as CallInstruction;
if (call == null || call.OpCode == OpCode.NewObj)
return;
@event = null;
var instr = b.Instructions;
if (instr.Count != 5 || !b.FinalInstruction.MatchNop())
return false;
// stloc v(newobj EventSetter..ctor())
if (!instr.ElementAt(0).MatchStLoc(out var v, out var initializer))
return false;
if (!(initializer is NewObj newObj
&& newObj.Method.DeclaringType.FullName == "System.Windows.EventSetter"
&& newObj.Arguments.Count == 0))
{
return false;
}
//callvirt set_Event(ldloc v, ldsfld eventName)
if (!(instr.ElementAt(1) is CallVirt setEventCall && setEventCall.Arguments.Count == 2))
return false;
if (!setEventCall.Method.IsAccessor)
return false;
if (!setEventCall.Arguments[0].MatchLdLoc(v))
return false;
if (setEventCall.Method.Name != "set_Event")
return false;
if (!setEventCall.Arguments[1].MatchLdsFld(out var eventField))
return false;
string eventName = eventField.Name;
if (eventName.EndsWith("Event"))
{
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))
return false;
if (!setHandlerCall.Method.IsAccessor)
return false;
if (!setHandlerCall.Arguments[0].MatchLdLoc(v))
return false;
if (setHandlerCall.Method.Name != "set_Handler")
return false;
if (!MatchEventHandlerCreation(setHandlerCall.Arguments[1], out string handlerName))
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))
return false;
if (addCall.Method.Name != "Add")
return false;
if (!(addCall.Arguments[0] is CallVirt getSettersCall && getSettersCall.Arguments.Count == 1))
return false;
if (!getSettersCall.Method.IsAccessor)
return false;
if (getSettersCall.Method.Name != "get_Setters")
return false;
if (!getSettersCall.Arguments[0].MatchCastClass(out var arg, out var type))
return false;
if (type.FullName != "System.Windows.Style")
return false;
if (!(arg.MatchLdLoc(out var t) && t.Kind == VariableKind.Parameter && t.Index == 1))
return false;
if (!addCall.Arguments[1].MatchLdLoc(v))
return false;
return true;
}
bool MatchSimpleEventRegistration(ILInstruction inst, out EventRegistration @event)
{
@event = null;
if (!(inst is CallInstruction call) || call.OpCode == OpCode.NewObj)
return false;
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 });
return false;
}
@event = new EventRegistration { EventName = eventName, MethodName = handlerName };
return true;
}
bool IsAddAttachedEvent(CallInstruction call, out string eventName, out string handlerName)
@ -208,14 +298,7 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -208,14 +298,7 @@ namespace ILSpy.BamlDecompiler.Rewrite
{
eventName = eventName.Remove(eventName.Length - "Event".Length);
}
var newObj = call.Arguments[2] as NewObj;
if (newObj == null || newObj.Arguments.Count != 2)
return false;
var ldftn = newObj.Arguments[1];
if (ldftn.OpCode != OpCode.LdFtn && ldftn.OpCode != OpCode.LdVirtFtn)
return false;
handlerName = ((IInstructionWithMethodOperand)ldftn).Method.Name;
return true;
return MatchEventHandlerCreation(call.Arguments[2], out handlerName);
}
return false;
@ -235,18 +318,23 @@ namespace ILSpy.BamlDecompiler.Rewrite @@ -235,18 +318,23 @@ namespace ILSpy.BamlDecompiler.Rewrite
return false;
}
eventName = addMethod.Name.Substring("add_".Length);
var newObj = call.Arguments[1] as NewObj;
if (newObj == null || newObj.Arguments.Count != 2)
return false;
var ldftn = newObj.Arguments[1];
if (ldftn.OpCode != OpCode.LdFtn && ldftn.OpCode != OpCode.LdVirtFtn)
return false;
handlerName = ((IInstructionWithMethodOperand)ldftn).Method.Name;
handlerName = XamlUtils.EscapeName(handlerName);
return true;
return MatchEventHandlerCreation(call.Arguments[1], out handlerName);
}
return false;
}
bool MatchEventHandlerCreation(ILInstruction inst, out string handlerName)
{
handlerName = "";
if (!(inst is NewObj newObj) || newObj.Arguments.Count != 2)
return false;
var ldftn = newObj.Arguments[1];
if (ldftn.OpCode != OpCode.LdFtn && ldftn.OpCode != OpCode.LdVirtFtn)
return false;
handlerName = ((IInstructionWithMethodOperand)ldftn).Method.Name;
handlerName = XamlUtils.EscapeName(handlerName);
return true;
}
}
}

Loading…
Cancel
Save