From a75e2a3c96d14a0abb6c94730f7522092eed6be0 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 3 Jun 2011 12:15:35 +0200 Subject: [PATCH] add ConnectMethodDecompiler --- ILSpy.BamlDecompiler/BamlResourceEntryNode.cs | 38 +++++++++ .../ConnectMethodDecompiler.cs | 78 +++++-------------- .../ILSpy.BamlDecompiler.csproj | 1 + .../Tests/Cases/AttachedEvent.xaml | 3 + .../Tests/Cases/AttachedEvent.xaml.cs | 31 ++++++++ .../Tests/ILSpy.BamlDecompiler.Tests.csproj | 5 ++ ILSpy.BamlDecompiler/Tests/TestRunner.cs | 6 ++ ILSpy/ILSpy.csproj | 1 - ILSpy/Languages/CSharpLanguage.cs | 1 - 9 files changed, 103 insertions(+), 61 deletions(-) rename {ILSpy => ILSpy.BamlDecompiler}/ConnectMethodDecompiler.cs (64%) create mode 100644 ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml create mode 100644 ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml.cs diff --git a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs index b79492d1f..f6d1addf7 100644 --- a/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs +++ b/ILSpy.BamlDecompiler/BamlResourceEntryNode.cs @@ -59,11 +59,22 @@ namespace ILSpy.BamlDecompiler XDocument xamlDocument; using (XmlBamlReader reader = new XmlBamlReader(stream, new CecilTypeResolver(resolver, asm))) xamlDocument = XDocument.Load(reader); + ConvertConnectionIds(xamlDocument, asm); ConvertToEmptyElements(xamlDocument.Root); MoveNamespacesToRoot(xamlDocument); return xamlDocument; } + static void ConvertConnectionIds(XDocument xamlDocument, AssemblyDefinition asm) + { + var attr = xamlDocument.Root.Attribute(XName.Get("Class", XmlBamlReader.XWPFNamespace)); + if (attr != null) { + string fullTypeName = attr.Value; + var mappings = new ConnectMethodDecompiler(asm).DecompileEventMappings(fullTypeName); + RemoveConnectionIds(xamlDocument.Root, mappings); + } + } + static void MoveNamespacesToRoot(XDocument xamlDocument) { var additionalXmlns = new List { @@ -98,5 +109,32 @@ namespace ILSpy.BamlDecompiler ConvertToEmptyElements(el); } } + + static void RemoveConnectionIds(XElement element, Dictionary eventMappings) + { + foreach (var child in element.Elements()) + RemoveConnectionIds(child, eventMappings); + + var removableAttrs = new List(); + var addableAttrs = new List(); + foreach (var attr in element.Attributes(XName.Get("ConnectionId", XmlBamlReader.XWPFNamespace))) { + int id; + if (int.TryParse(attr.Value, out id) && eventMappings.ContainsKey(id)) { + var map = eventMappings[id]; + foreach (var entry in map) { + string xmlns = ""; // TODO : implement xmlns resolver! + if (entry.IsAttached) { + addableAttrs.Add(new XAttribute(xmlns + entry.AttachSourceType.Name + "." + entry.EventName, entry.MethodName)); + } else { + addableAttrs.Add(new XAttribute(xmlns + entry.EventName, entry.MethodName)); + } + } + removableAttrs.Add(attr); + } + } + foreach (var attr in removableAttrs) + attr.Remove(); + element.Add(addableAttrs); + } } } \ No newline at end of file diff --git a/ILSpy/ConnectMethodDecompiler.cs b/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs similarity index 64% rename from ILSpy/ConnectMethodDecompiler.cs rename to ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs index 7cb2c1760..2ae4fd076 100644 --- a/ILSpy/ConnectMethodDecompiler.cs +++ b/ILSpy.BamlDecompiler/ConnectMethodDecompiler.cs @@ -1,47 +1,34 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team +// This code is distributed under the MS-PL (for details please see \doc\MS-PL.txt) using System; using System.Collections.Generic; -using System.Diagnostics; using System.Linq; + using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.ILAst; using Mono.Cecil; -using Mono.Cecil.Cil; -namespace ICSharpCode.ILSpy.Baml +namespace ILSpy.BamlDecompiler { - [Serializable] + /// + /// Represents an event registration of a XAML code-behind class. + /// sealed class EventRegistration { - public string EventName, MethodName, AttachSourceType; + public string EventName, MethodName; + public TypeDefinition AttachSourceType; public bool IsAttached; } /// - /// Description of ConnectMethodDecompiler. + /// Decompiles event and name mappings of XAML code-behind classes. /// - sealed class ConnectMethodDecompiler : MarshalByRefObject + sealed class ConnectMethodDecompiler { - LoadedAssembly assembly; + AssemblyDefinition assembly; - public ConnectMethodDecompiler(LoadedAssembly assembly) + public ConnectMethodDecompiler(AssemblyDefinition assembly) { this.assembly = assembly; } @@ -49,7 +36,7 @@ namespace ICSharpCode.ILSpy.Baml public Dictionary DecompileEventMappings(string fullTypeName) { var result = new Dictionary(); - TypeDefinition type = this.assembly.AssemblyDefinition.MainModule.GetType(fullTypeName); + TypeDefinition type = this.assembly.MainModule.GetType(fullTypeName); if (type == null) return result; @@ -98,7 +85,8 @@ namespace ICSharpCode.ILSpy.Baml foreach (var node in block.Body) { var expr = node as ILExpression; - string eventName, handlerName, attachSource; + string eventName, handlerName; + TypeDefinition attachSource; if (IsAddEvent(expr, out eventName, out handlerName)) events.Add(new EventRegistration { EventName = eventName, @@ -116,11 +104,11 @@ namespace ICSharpCode.ILSpy.Baml return events.ToArray(); } - bool IsAddAttachedEvent(ILExpression expr, out string eventName, out string handlerName, out string attachSource) + bool IsAddAttachedEvent(ILExpression expr, out string eventName, out string handlerName, out TypeDefinition attachSource) { eventName = ""; handlerName = ""; - attachSource = ""; + attachSource = null; if (expr == null || !(expr.Code == ILCode.Callvirt || expr.Code == ILCode.Call)) return false; @@ -133,7 +121,7 @@ namespace ICSharpCode.ILSpy.Baml if (arg.Code != ILCode.Ldsfld || arg.Arguments.Any() || !(arg.Operand is FieldReference)) return false; FieldReference fldRef = (FieldReference)arg.Operand; - attachSource = GetAssemblyQualifiedName(fldRef.DeclaringType); + attachSource = fldRef.DeclaringType.Resolve(); eventName = fldRef.Name; if (eventName.EndsWith("Event") && eventName.Length > "Event".Length) eventName = eventName.Remove(eventName.Length - "Event".Length); @@ -153,18 +141,6 @@ namespace ICSharpCode.ILSpy.Baml return false; } - string GetAssemblyQualifiedName(TypeReference declaringType) - { - string fullName = declaringType.FullName; - - if (declaringType.Scope is AssemblyNameReference) - fullName += ", " + ((AssemblyNameReference)declaringType.Scope).FullName; - else if (declaringType.Scope is ModuleDefinition) - fullName += ", " + ((ModuleDefinition)declaringType.Scope).Assembly.FullName; - - return fullName; - } - bool IsAddEvent(ILExpression expr, out string eventName, out string handlerName) { eventName = ""; @@ -193,20 +169,4 @@ namespace ICSharpCode.ILSpy.Baml return false; } } - - sealed class AssemblyResolver : MarshalByRefObject - { - LoadedAssembly assembly; - - public AssemblyResolver(LoadedAssembly assembly) - { - this.assembly = assembly; - } - - public string FindAssembly(string name) - { - var asm = assembly.LookupReferencedAssembly(name); - return asm == null ? null : asm.FileName; - } - } } diff --git a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj index adc87221c..88aa520f9 100644 --- a/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj +++ b/ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj @@ -77,6 +77,7 @@ + diff --git a/ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml b/ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml new file mode 100644 index 000000000..866abc9b6 --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml.cs b/ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml.cs new file mode 100644 index 000000000..f0ec0f875 --- /dev/null +++ b/ILSpy.BamlDecompiler/Tests/Cases/AttachedEvent.xaml.cs @@ -0,0 +1,31 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; + +namespace ILSpy.BamlDecompiler.Tests.Cases +{ + /// + /// Interaction logic for AttachedEvent.xaml + /// + public partial class AttachedEvent : Window + { + public AttachedEvent() + { + InitializeComponent(); + } + + void GridAccessKeyPressed(object sender, AccessKeyPressedEventArgs e) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj b/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj index f6b42c5c0..95c91a8d6 100644 --- a/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj +++ b/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj @@ -66,6 +66,10 @@ + + AttachedEvent.xaml + Code + Resources.xaml Code @@ -110,6 +114,7 @@ + diff --git a/ILSpy.BamlDecompiler/Tests/TestRunner.cs b/ILSpy.BamlDecompiler/Tests/TestRunner.cs index 8a6a5a830..6469bc081 100644 --- a/ILSpy.BamlDecompiler/Tests/TestRunner.cs +++ b/ILSpy.BamlDecompiler/Tests/TestRunner.cs @@ -55,6 +55,12 @@ namespace ILSpy.BamlDecompiler.Tests RunTest("cases/avalondockcommon"); } + [Test] + public void AttachedEvent() + { + RunTest("cases/attachedevent"); + } + #region RunTest void RunTest(string name) { diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 9090a9a0a..97f7d2e76 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -98,7 +98,6 @@ - diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 2bca8b859..fb8a84a35 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -31,7 +31,6 @@ using System.Xml; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Ast; using ICSharpCode.Decompiler.Ast.Transforms; -using ICSharpCode.ILSpy.Baml; using ICSharpCode.ILSpy.XmlDoc; using ICSharpCode.NRefactory.CSharp; using Mono.Cecil;