Browse Source

Fix #2106: EventSetter is lost.

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

158
ILSpy.BamlDecompiler/Rewrite/ConnectionIdRewritePass.cs

@ -59,11 +59,21 @@ namespace ILSpy.BamlDecompiler.Rewrite
foreach (var entry in eventMappings[index].value) foreach (var entry in eventMappings[index].value)
{ {
string xmlns = ""; // TODO : implement xmlns resolver! string xmlns = ""; // TODO : implement xmlns resolver!
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)); element.Add(new XAttribute(xmlns + entry.EventName, entry.MethodName));
} }
} }
} }
} }
}
List<(LongSet, EventRegistration[])> DecompileEventMappings(XamlContext ctx, XDocument document) List<(LongSet, EventRegistration[])> DecompileEventMappings(XamlContext ctx, XDocument document)
{ {
@ -133,8 +143,9 @@ namespace ILSpy.BamlDecompiler.Rewrite
{ {
foreach (var section in ilSwitch.Sections) foreach (var section in ilSwitch.Sections)
{ {
var events = FindEvents(section.Body); var events = new List<EventRegistration>();
result.Add((section.Labels, events)); FindEvents(section.Body, events);
result.Add((section.Labels, events.ToArray()));
} }
} }
else else
@ -147,47 +158,126 @@ namespace ILSpy.BamlDecompiler.Rewrite
continue; continue;
if (!comp.Right.MatchLdcI4(out int id)) if (!comp.Right.MatchLdcI4(out int id))
continue; continue;
var events = FindEvents(comp.Kind == ComparisonKind.Inequality var inst = comp.Kind == ComparisonKind.Inequality
? ifInst.FalseInst ? ifInst.FalseInst
: ifInst.TrueInst); : ifInst.TrueInst;
result.Add((new LongSet(id), events)); 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) switch (inst)
{ {
case Block _: case Block b:
foreach (var node in ((Block)inst).Instructions) if (MatchEventSetterCreation(b, out var @event))
{
events.Add(@event);
break;
}
foreach (var node in b.Instructions)
{ {
FindEvents(node, events); if (MatchSimpleEventRegistration(node, out @event))
events.Add(@event);
} }
FindEvents(((Block)inst).FinalInstruction, events);
break; break;
case Branch br: case Branch br:
return FindEvents(br.TargetBlock); FindEvents(br.TargetBlock, events);
break;
default: default:
FindEvents(inst, events); if (MatchSimpleEventRegistration(inst, out @event))
events.Add(@event);
break; 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; @event = null;
if (call == null || call.OpCode == OpCode.NewObj) var instr = b.Instructions;
return; 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) if (!IsAddEvent(call, out string eventName, out string handlerName)
|| IsAddAttachedEvent(call, out eventName, out 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) bool IsAddAttachedEvent(CallInstruction call, out string eventName, out string handlerName)
@ -208,14 +298,7 @@ namespace ILSpy.BamlDecompiler.Rewrite
{ {
eventName = eventName.Remove(eventName.Length - "Event".Length); eventName = eventName.Remove(eventName.Length - "Event".Length);
} }
var newObj = call.Arguments[2] as NewObj; return MatchEventHandlerCreation(call.Arguments[2], out handlerName);
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 false; return false;
@ -235,8 +318,16 @@ namespace ILSpy.BamlDecompiler.Rewrite
return false; return false;
} }
eventName = addMethod.Name.Substring("add_".Length); eventName = addMethod.Name.Substring("add_".Length);
var newObj = call.Arguments[1] as NewObj; return MatchEventHandlerCreation(call.Arguments[1], out handlerName);
if (newObj == null || newObj.Arguments.Count != 2) }
return false;
}
bool MatchEventHandlerCreation(ILInstruction inst, out string handlerName)
{
handlerName = "";
if (!(inst is NewObj newObj) || newObj.Arguments.Count != 2)
return false; return false;
var ldftn = newObj.Arguments[1]; var ldftn = newObj.Arguments[1];
if (ldftn.OpCode != OpCode.LdFtn && ldftn.OpCode != OpCode.LdVirtFtn) if (ldftn.OpCode != OpCode.LdFtn && ldftn.OpCode != OpCode.LdVirtFtn)
@ -245,8 +336,5 @@ namespace ILSpy.BamlDecompiler.Rewrite
handlerName = XamlUtils.EscapeName(handlerName); handlerName = XamlUtils.EscapeName(handlerName);
return true; return true;
} }
return false;
}
} }
} }

Loading…
Cancel
Save