From a683ba51ff3bd40edd0ebfa75a86441f08936925 Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Sat, 21 May 2011 23:07:39 +1000 Subject: [PATCH 01/16] Removed redundant parameter. --- ILSpy/TreeNodes/Analyzer/Helpers.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ILSpy/TreeNodes/Analyzer/Helpers.cs b/ILSpy/TreeNodes/Analyzer/Helpers.cs index bef4e486a..b773ad875 100644 --- a/ILSpy/TreeNodes/Analyzer/Helpers.cs +++ b/ILSpy/TreeNodes/Analyzer/Helpers.cs @@ -67,11 +67,11 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return FindMethodUsageInType(method.DeclaringType, method) ?? method; } - var typeUsage = GetOriginalCodeLocation(method.DeclaringType, method); + var typeUsage = GetOriginalCodeLocation(method.DeclaringType); return typeUsage ?? method; } - public static MethodDefinition GetOriginalCodeLocation(TypeDefinition type, MethodDefinition method) + public static MethodDefinition GetOriginalCodeLocation(TypeDefinition type) { if (type != null && type.DeclaringType != null && type.IsCompilerGenerated()) { MethodDefinition constructor = GetTypeConstructor(type); From eba91caf6cd84e99c41f0885e268354723adec3e Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Sat, 21 May 2011 23:12:35 +1000 Subject: [PATCH 02/16] Analyzer: further improvements to where-used analysis for virtual methods. --- .../AnalyzedVirtualMethodUsedByTreeNode.cs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs index 993ef36d7..26f5e4c65 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedVirtualMethodUsedByTreeNode.cs @@ -89,7 +89,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer var BaseMethods = TypesHierarchyHelpers.FindBaseMethods(analyzedMethod).ToArray(); if (BaseMethods.Length > 0) { baseMethod = BaseMethods[BaseMethods.Length - 1]; - } + } else + baseMethod = analyzedMethod; possibleTypes = new List(); @@ -119,15 +120,24 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer MethodReference mr = instr.Operand as MethodReference; if (mr != null && mr.Name == name) { // explicit call to the requested method - if (Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) && mr.Resolve() == analyzedMethod) { + if (instr.OpCode.Code == Code.Call + && Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) + && mr.Resolve() == analyzedMethod) { found = true; prefix = "(as base) "; break; } // virtual call to base method - if (instr.OpCode.Code == Code.Callvirt && Helpers.IsReferencedBy(baseMethod.DeclaringType, mr.DeclaringType) && mr.Resolve() == baseMethod) { - found = true; - break; + if (instr.OpCode.Code == Code.Callvirt) { + MethodDefinition md = mr.Resolve(); + if (md == null) { + // cannot resolve the operand, so ignore this method + break; + } + if (md == baseMethod) { + found = true; + break; + } } } } From 6b449d5bf3914f8e91038b9affbadb367a39c6a2 Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 16:12:49 +1000 Subject: [PATCH 03/16] Move resource tree nodes to separate folder. --- ILSpy/ILSpy.csproj | 7 ++++--- ILSpy/TreeNodes/{ => ResourceNodes}/ResourceEntryNode.cs | 0 ILSpy/TreeNodes/{ => ResourceNodes}/ResourceTreeNode.cs | 0 ILSpy/TreeNodes/{ => ResourceNodes}/XamlResourceNode.cs | 0 4 files changed, 4 insertions(+), 3 deletions(-) rename ILSpy/TreeNodes/{ => ResourceNodes}/ResourceEntryNode.cs (100%) rename ILSpy/TreeNodes/{ => ResourceNodes}/ResourceTreeNode.cs (100%) rename ILSpy/TreeNodes/{ => ResourceNodes}/XamlResourceNode.cs (100%) diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 0bda1e382..1c7bcaadf 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -159,7 +159,7 @@ - + @@ -218,9 +218,9 @@ - + - + @@ -312,5 +312,6 @@ ICSharpCode.TreeView + \ No newline at end of file diff --git a/ILSpy/TreeNodes/ResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs similarity index 100% rename from ILSpy/TreeNodes/ResourceEntryNode.cs rename to ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs diff --git a/ILSpy/TreeNodes/ResourceTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs similarity index 100% rename from ILSpy/TreeNodes/ResourceTreeNode.cs rename to ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs diff --git a/ILSpy/TreeNodes/XamlResourceNode.cs b/ILSpy/TreeNodes/ResourceNodes/XamlResourceNode.cs similarity index 100% rename from ILSpy/TreeNodes/XamlResourceNode.cs rename to ILSpy/TreeNodes/ResourceNodes/XamlResourceNode.cs From 68fe9617ba5ca15f3ba78df864aedeb7af58887d Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 16:26:38 +1000 Subject: [PATCH 04/16] Split classes into separate files. --- .../ResourceNodes/IResourceNodeFactory.cs | 33 ++++++++ .../ResourceNodes/ResourceTreeNode.cs | 65 ++------------- .../ResourceNodes/ResourcesFileTreeNode.cs | 79 +++++++++++++++++++ 3 files changed, 117 insertions(+), 60 deletions(-) create mode 100644 ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs create mode 100644 ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs diff --git a/ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs b/ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs new file mode 100644 index 000000000..49d5f4893 --- /dev/null +++ b/ILSpy/TreeNodes/ResourceNodes/IResourceNodeFactory.cs @@ -0,0 +1,33 @@ +// 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. + +using System; +using System.IO; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.TreeNodes +{ + /// + /// This interface allows plugins to create custom nodes for resources. + /// + public interface IResourceNodeFactory + { + ILSpyTreeNode CreateNode(Resource resource); + ILSpyTreeNode CreateNode(string key, Stream data); + } +} diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs index 5e79845ba..aecfcc6a3 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs @@ -34,6 +34,10 @@ using Mono.Cecil; namespace ICSharpCode.ILSpy.TreeNodes { + /// + /// This is the default resource entry tree node, which is used if no specific + /// exists for the given resource type. + /// public class ResourceTreeNode : ILSpyTreeNode { Resource r; @@ -132,63 +136,4 @@ namespace ICSharpCode.ILSpy.TreeNodes return result ?? new ResourceTreeNode(resource); } } - - /// - /// This interface allows plugins to create custom nodes for resources. - /// - public interface IResourceNodeFactory - { - ILSpyTreeNode CreateNode(Resource resource); - ILSpyTreeNode CreateNode(string key, Stream data); - } - - [Export(typeof(IResourceNodeFactory))] - sealed class ResourcesFileTreeNodeFactory : IResourceNodeFactory - { - public ILSpyTreeNode CreateNode(Resource resource) - { - EmbeddedResource er = resource as EmbeddedResource; - if (er != null && er.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) { - return new ResourcesFileTreeNode(er); - } - return null; - } - - public ILSpyTreeNode CreateNode(string key, Stream data) - { - return null; - } - } - - sealed class ResourcesFileTreeNode : ResourceTreeNode - { - public ResourcesFileTreeNode(EmbeddedResource er) : base(er) - { - this.LazyLoading = true; - } - - public override object Icon - { - get { return Images.ResourceResourcesFile; } - } - - protected override void LoadChildren() - { - EmbeddedResource er = this.Resource as EmbeddedResource; - if (er != null) { - Stream s = er.GetResourceStream(); - s.Position = 0; - ResourceReader reader; - try { - reader = new ResourceReader(s); - } catch (ArgumentException) { - return; - } - foreach (DictionaryEntry entry in reader.Cast().OrderBy(e => e.Key.ToString())) { - if (entry.Value is Stream) - Children.Add(ResourceEntryNode.Create(entry.Key.ToString(), (Stream)entry.Value)); - } - } - } - } -} +} \ No newline at end of file diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs new file mode 100644 index 000000000..0397841a0 --- /dev/null +++ b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs @@ -0,0 +1,79 @@ +// 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. + +using System; +using System.Collections; +using System.ComponentModel.Composition; +using System.IO; +using System.Linq; +using System.Resources; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.TreeNodes +{ + [Export(typeof(IResourceNodeFactory))] + sealed class ResourcesFileTreeNodeFactory : IResourceNodeFactory + { + public ILSpyTreeNode CreateNode(Resource resource) + { + EmbeddedResource er = resource as EmbeddedResource; + if (er != null && er.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) { + return new ResourcesFileTreeNode(er); + } + return null; + } + + public ILSpyTreeNode CreateNode(string key, Stream data) + { + return null; + } + } + + sealed class ResourcesFileTreeNode : ResourceTreeNode + { + public ResourcesFileTreeNode(EmbeddedResource er) + : base(er) + { + this.LazyLoading = true; + } + + public override object Icon + { + get { return Images.ResourceResourcesFile; } + } + + protected override void LoadChildren() + { + EmbeddedResource er = this.Resource as EmbeddedResource; + if (er != null) { + Stream s = er.GetResourceStream(); + s.Position = 0; + ResourceReader reader; + try { + reader = new ResourceReader(s); + } + catch (ArgumentException) { + return; + } + foreach (DictionaryEntry entry in reader.Cast().OrderBy(e => e.Key.ToString())) + if (entry.Value is Stream) + Children.Add(ResourceEntryNode.Create(entry.Key.ToString(), (Stream)entry.Value)); + } + } + } +} From 311a5bb2647408d75279053489534cdd6963a8c8 Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 16:29:21 +1000 Subject: [PATCH 05/16] Tidied 'using' statements. --- ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs index 43638064d..e4b165680 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs @@ -17,14 +17,10 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.IO; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; using System.ComponentModel.Composition; +using System.IO; using System.Windows.Controls; using System.Windows.Media.Imaging; -using ICSharpCode.AvalonEdit.Highlighting; using ICSharpCode.Decompiler; using ICSharpCode.ILSpy.TextView; using Microsoft.Win32; From 43e97197e1115fdf75e8161f9482090f05f61b1c Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 16:31:30 +1000 Subject: [PATCH 06/16] Moved BamlResourceEntryNode class to own file in ResourceNodes folder. --- ILSpy/BamlDecompiler.cs | 81 -------------- ILSpy/ILSpy.csproj | 3 + .../ResourceNodes/BamlResourceEntryNode.cs | 104 ++++++++++++++++++ 3 files changed, 107 insertions(+), 81 deletions(-) create mode 100644 ILSpy/TreeNodes/ResourceNodes/BamlResourceEntryNode.cs diff --git a/ILSpy/BamlDecompiler.cs b/ILSpy/BamlDecompiler.cs index 07c60b13e..19341812f 100644 --- a/ILSpy/BamlDecompiler.cs +++ b/ILSpy/BamlDecompiler.cs @@ -361,85 +361,4 @@ namespace ICSharpCode.ILSpy.Baml } } } - - [Export(typeof(IResourceNodeFactory))] - sealed class BamlResourceNodeFactory : IResourceNodeFactory - { - public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) - { - return null; - } - - public ILSpyTreeNode CreateNode(string key, Stream data) - { - if (key.EndsWith(".baml", StringComparison.OrdinalIgnoreCase)) - return new BamlResourceEntryNode(key, data); - else - return null; - } - } - - sealed class BamlResourceEntryNode : ResourceEntryNode - { - public BamlResourceEntryNode(string key, Stream data) : base(key, data) - { - } - - internal override bool View(DecompilerTextView textView) - { - AvalonEditTextOutput output = new AvalonEditTextOutput(); - IHighlightingDefinition highlighting = null; - - textView.RunWithCancellation( - token => Task.Factory.StartNew( - () => { - try { - if (LoadBaml(output)) - highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml"); - } catch (Exception ex) { - output.Write(ex.ToString()); - } - return output; - }), - t => textView.ShowNode(t.Result, this, highlighting) - ); - return true; - } - - bool LoadBaml(AvalonEditTextOutput output) - { - var asm = this.Ancestors().OfType().FirstOrDefault().LoadedAssembly; - - AppDomain bamlDecompilerAppDomain = null; - try { - BamlDecompiler decompiler = CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, asm.FileName); - - MemoryStream bamlStream = new MemoryStream(); - Data.Position = 0; - Data.CopyTo(bamlStream); - - output.Write(decompiler.DecompileBaml(bamlStream, asm.FileName, new ConnectMethodDecompiler(asm), new AssemblyResolver(asm))); - return true; - } finally { - if (bamlDecompilerAppDomain != null) - AppDomain.Unload(bamlDecompilerAppDomain); - } - } - - public static BamlDecompiler CreateBamlDecompilerInAppDomain(ref AppDomain appDomain, string assemblyFileName) - { - if (appDomain == null) { - // Construct and initialize settings for a second AppDomain. - AppDomainSetup bamlDecompilerAppDomainSetup = new AppDomainSetup(); -// bamlDecompilerAppDomainSetup.ApplicationBase = "file:///" + Path.GetDirectoryName(assemblyFileName); - bamlDecompilerAppDomainSetup.DisallowBindingRedirects = false; - bamlDecompilerAppDomainSetup.DisallowCodeDownload = true; - bamlDecompilerAppDomainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; - - // Create the second AppDomain. - appDomain = AppDomain.CreateDomain("BamlDecompiler AD", null, bamlDecompilerAppDomainSetup); - } - return (BamlDecompiler)appDomain.CreateInstanceAndUnwrap(typeof(BamlDecompiler).Assembly.FullName, typeof(BamlDecompiler).FullName); - } - } } \ No newline at end of file diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 1c7bcaadf..0fd9f90e8 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -94,6 +94,7 @@ + @@ -159,6 +160,8 @@ + + diff --git a/ILSpy/TreeNodes/ResourceNodes/BamlResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/BamlResourceEntryNode.cs new file mode 100644 index 000000000..9bb46ba0a --- /dev/null +++ b/ILSpy/TreeNodes/ResourceNodes/BamlResourceEntryNode.cs @@ -0,0 +1,104 @@ +// 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. + +using System; +using System.ComponentModel.Composition; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using ICSharpCode.AvalonEdit.Highlighting; +using ICSharpCode.ILSpy.TextView; +using ICSharpCode.ILSpy.TreeNodes; + +namespace ICSharpCode.ILSpy.Baml +{ + [Export(typeof(IResourceNodeFactory))] + sealed class BamlResourceNodeFactory : IResourceNodeFactory + { + public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) + { + return null; + } + + public ILSpyTreeNode CreateNode(string key, Stream data) + { + if (key.EndsWith(".baml", StringComparison.OrdinalIgnoreCase)) + return new BamlResourceEntryNode(key, data); + else + return null; + } + } + + sealed class BamlResourceEntryNode : ResourceEntryNode + { + public BamlResourceEntryNode(string key, Stream data) + : base(key, data) + { + } + + internal override bool View(DecompilerTextView textView) + { + AvalonEditTextOutput output = new AvalonEditTextOutput(); + IHighlightingDefinition highlighting = null; + textView.RunWithCancellation(token => Task.Factory.StartNew(() => { + try { + if (LoadBaml(output)) + highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml"); + } + catch (Exception ex) { + output.Write(ex.ToString()); + } + return output; + }), t => textView.ShowNode(t.Result, this, highlighting)); + return true; + } + + bool LoadBaml(AvalonEditTextOutput output) + { + var asm = this.Ancestors().OfType().FirstOrDefault().LoadedAssembly; + AppDomain bamlDecompilerAppDomain = null; + try { + BamlDecompiler decompiler = CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, asm.FileName); + MemoryStream bamlStream = new MemoryStream(); + Data.Position = 0; + Data.CopyTo(bamlStream); + output.Write(decompiler.DecompileBaml(bamlStream, asm.FileName, new ConnectMethodDecompiler(asm), new AssemblyResolver(asm))); + return true; + } + finally { + if (bamlDecompilerAppDomain != null) + AppDomain.Unload(bamlDecompilerAppDomain); + } + } + + public static BamlDecompiler CreateBamlDecompilerInAppDomain(ref AppDomain appDomain, string assemblyFileName) + { + if (appDomain == null) { + // Construct and initialize settings for a second AppDomain. + AppDomainSetup bamlDecompilerAppDomainSetup = new AppDomainSetup(); + // bamlDecompilerAppDomainSetup.ApplicationBase = "file:///" + Path.GetDirectoryName(assemblyFileName); + bamlDecompilerAppDomainSetup.DisallowBindingRedirects = false; + bamlDecompilerAppDomainSetup.DisallowCodeDownload = true; + bamlDecompilerAppDomainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; + // Create the second AppDomain. + appDomain = AppDomain.CreateDomain("BamlDecompiler AD", null, bamlDecompilerAppDomainSetup); + } + return (BamlDecompiler)appDomain.CreateInstanceAndUnwrap(typeof(BamlDecompiler).Assembly.FullName, typeof(BamlDecompiler).FullName); + } + } +} From 4ede9627212de6386c76c02db09cfc0835c6ca8e Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 16:41:59 +1000 Subject: [PATCH 07/16] Added resource node for general xml-based resources (xml, xsd, xslt) --- .../ResourceNodes/XmlResourceNode.cs | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs diff --git a/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs b/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs new file mode 100644 index 000000000..db577d8d9 --- /dev/null +++ b/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs @@ -0,0 +1,88 @@ +// 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. + +using System; +using System.ComponentModel.Composition; +using System.IO; +using System.Threading.Tasks; + +using ICSharpCode.AvalonEdit.Highlighting; +using ICSharpCode.ILSpy.TextView; +using ICSharpCode.ILSpy.TreeNodes; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.Xaml +{ + [Export(typeof(IResourceNodeFactory))] + sealed class XmlResourceNodeFactory : IResourceNodeFactory + { + private readonly static string[] xmlFileExtensions = { ".xml", ".xsd", ".xslt" }; + + public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) + { + EmbeddedResource er = resource as EmbeddedResource; + if (er != null) + return CreateNode(er.Name, er.GetResourceStream()); + return null; + } + + public ILSpyTreeNode CreateNode(string key, Stream data) + { + foreach (string fileExt in xmlFileExtensions) + if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) + return new XmlResourceEntryNode(key, data); + return null; + } + } + + sealed class XmlResourceEntryNode : ResourceEntryNode + { + string xaml; + + public XmlResourceEntryNode(string key, Stream data) : base(key, data) + { + } + + internal override bool View(DecompilerTextView textView) + { + AvalonEditTextOutput output = new AvalonEditTextOutput(); + IHighlightingDefinition highlighting = null; + + textView.RunWithCancellation( + token => Task.Factory.StartNew( + () => { + try { + // cache read XAML because stream will be closed after first read + if (xaml == null) { + using (var reader = new StreamReader(Data)) { + xaml = reader.ReadToEnd(); + } + } + output.Write(xaml); + highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml"); + } catch (Exception ex) { + output.Write(ex.ToString()); + } + return output; + }), + t => textView.ShowNode(t.Result, this, highlighting) + ); + return true; + } + } +} From fb3523b8302249bfca553c947d2dfc50f385dc7f Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 18:06:12 +1000 Subject: [PATCH 08/16] Handle resources stored as byte arrays. --- ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs index 0397841a0..a99e2a989 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ResourcesFileTreeNode.cs @@ -70,9 +70,12 @@ namespace ICSharpCode.ILSpy.TreeNodes catch (ArgumentException) { return; } - foreach (DictionaryEntry entry in reader.Cast().OrderBy(e => e.Key.ToString())) + foreach (DictionaryEntry entry in reader.Cast().OrderBy(e => e.Key.ToString())) { if (entry.Value is Stream) Children.Add(ResourceEntryNode.Create(entry.Key.ToString(), (Stream)entry.Value)); + else if (entry.Value is byte[]) + Children.Add(ResourceEntryNode.Create(entry.Key.ToString(), new MemoryStream((byte[])entry.Value))); + } } } } From 2ca0012251b370e545689beb3d58ee8524d73fde Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Mon, 23 May 2011 18:28:38 +1000 Subject: [PATCH 09/16] Added specific icons for general xml-based resource nodes --- ILSpy/ILSpy.csproj | 9 ++++- ILSpy/Images/Images.cs | 3 ++ ILSpy/Images/ResourceXml.png | Bin 0 -> 465 bytes ILSpy/Images/ResourceXsd.png | Bin 0 -> 1398 bytes ILSpy/Images/ResourceXslt.png | Bin 0 -> 1357 bytes .../ResourceNodes/XmlResourceNode.cs | 38 +++++++++++++----- 6 files changed, 38 insertions(+), 12 deletions(-) create mode 100644 ILSpy/Images/ResourceXml.png create mode 100644 ILSpy/Images/ResourceXsd.png create mode 100644 ILSpy/Images/ResourceXslt.png diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 0fd9f90e8..34b7a4d40 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -94,7 +94,7 @@ - + @@ -160,6 +160,7 @@ + @@ -315,6 +316,10 @@ ICSharpCode.TreeView - + + + + + \ No newline at end of file diff --git a/ILSpy/Images/Images.cs b/ILSpy/Images/Images.cs index 8755e772e..8e8f2b08d 100644 --- a/ILSpy/Images/Images.cs +++ b/ILSpy/Images/Images.cs @@ -59,6 +59,9 @@ namespace ICSharpCode.ILSpy public static readonly BitmapImage Resource = LoadBitmap("Resource"); public static readonly BitmapImage ResourceImage = LoadBitmap("ResourceImage"); public static readonly BitmapImage ResourceResourcesFile = LoadBitmap("ResourceResourcesFile"); + public static readonly BitmapImage ResourceXml = LoadBitmap("ResourceXml"); + public static readonly BitmapImage ResourceXsd = LoadBitmap("ResourceXsd"); + public static readonly BitmapImage ResourceXslt = LoadBitmap("ResourceXslt"); public static readonly BitmapImage Class = LoadBitmap("Class"); public static readonly BitmapImage Struct = LoadBitmap("Struct"); diff --git a/ILSpy/Images/ResourceXml.png b/ILSpy/Images/ResourceXml.png new file mode 100644 index 0000000000000000000000000000000000000000..157feead5668e880b027eee9a68e28c52f0decb7 GIT binary patch literal 465 zcmV;?0WSWDP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02XvbSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8JLvUk0003*Nkl#TBt)1Y!kZ#EQe*>GW==L)eC!-2Uc#J?Gv| zCZ^=8#F(zu6{=NrPa3aCi~~;A_H9dm5JF@NI02Cx39WSq@c@57+}Aq*I7R?4kb0*O zuX040gjm-cPbmfU*;vRCU~X{GsNZYMZetrIS|mtz6{3yC)$_~(=w0*C*y{kW|Jt*d z02em}rlr7TDKRCeD}w0nb`I=7EQK9T-+@>*I8U!}mPL3>jYH=^nP^m`IRai<0JS;T zIJ}i^JA>g0qxlsu7UBVlvaq>GoM%PYPv)8H&KYUg0RtSwi^H+pkLDtIfP9g+4or`A zKpJ*1Pv;EiK%I;Jxj$giFd%tILck!-a7(0NKztYDKTUui{R;Zgt@B+400000NkvXX Hu0mjfohZ4O literal 0 HcmV?d00001 diff --git a/ILSpy/Images/ResourceXsd.png b/ILSpy/Images/ResourceXsd.png new file mode 100644 index 0000000000000000000000000000000000000000..4422be59eb79e22c51a50a7cdd56f75a3cbb90fb GIT binary patch literal 1398 zcmeHG|1;BZ7=KI7mrSm3azu9(zgXO<$hVs?bK0@VaiP?t{b0zh`X%CrO6$_)&RyTH zQG9X?HN;HY$mSN?nb_Qf!;H{2Y?wWL{2hAkd7jtvyzcqw^}44jl}aYK__!d12$ZCF z8jkLJG4U6OA&8QBE@|t{4@$rcs7zjA z&74`gUKg|>W6U3%b>A3y-IS}3KcnY`O zxi~4S6d^asUfB&6H8OD0i=B|krWf60-_5(7kBak{EH;sq&khJ9hD0uIF!2i|C7zTX zL=PU)XNW`GAI_X?mz~a#2%Ua$JsD(D#glw2%;~Ym1#`I{pJ}nlBSr+$v;hxw4mKA+ zc9@JgZYvvq8d}qp%Ga9jmwZpjDJr=a-iV$D@~)2RgYV3+cn`(}w={%Dv(>I#<}+Rd zBTGa>RLqB&U6Qo?ve`9|b0qG%?~C`?Ws#;ZBhjB6u5iwYVJSN+rijF7@6jy3W1Ou> zqeHZJT6QkC`o!nA99F}{f?i!ivKyz;-s`BMwmv?}i}2`xU7w?l7d{-@T1U!MsjHUu OUV)N8jctYPs0 literal 0 HcmV?d00001 diff --git a/ILSpy/Images/ResourceXslt.png b/ILSpy/Images/ResourceXslt.png new file mode 100644 index 0000000000000000000000000000000000000000..107c9f2a684ff0192696d1921fa9e3929b3b3a5d GIT binary patch literal 1357 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NSs56Z83KGlT!G@Ip2=ojDJ2XHwZfuxBBGr-`hCWxNB7i!xm(jbY3<}i+ovtv zHGSFcSu6MLU$|!9qIGjt9-OoK;JkH*7p^_BX#LT}n~pEraA5JK6DzlzT)E@i%AM!e z?Y_8f-<6HK&u-jvZp+>an-1OBdFb-)!&mkmyLNEv@r!$oUfy@?>%+FMPbYkRG2_6= zn}<)|JaXpNsq@!PoWFbe;{ChFPhGn4G%83fBye}`v3p?k6(U&{r>mskH7!_fB5*Oa{{R2+|NqZFfByXa z`ya>w`f(JDh5*(OxP3kam{_QeYm>a8!j|*x_jwshoNDGf8LQ++Ste@(m?loNfsN_1wT;GFBLkBV&c59&B3 aS;N>FT&|g0@%}j|J$SnMxvX Task.Factory.StartNew( () => { try { // cache read XAML because stream will be closed after first read - if (xaml == null) { + if (xml == null) { using (var reader = new StreamReader(Data)) { - xaml = reader.ReadToEnd(); + xml = reader.ReadToEnd(); } } - output.Write(xaml); + output.Write(xml); highlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml"); - } catch (Exception ex) { + } + catch (Exception ex) { output.Write(ex.ToString()); } return output; From 4c8ea69ddb7129fd72d4064497469be73d299138 Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Tue, 24 May 2011 13:37:24 +1000 Subject: [PATCH 10/16] Added rudimentary event raised-by analyzer. Only works for 'standard' events (ie events without custom add/remove methods). Only implementations are analyzed, so event declarations on interfaces are out as well. --- ILSpy/ILSpy.csproj | 1 + .../Analyzer/AnalyzedEventFiredByTreeNode.cs | 144 ++++++++++++++++++ .../Analyzer/AnalyzedEventTreeNode.cs | 6 + 3 files changed, 151 insertions(+) create mode 100644 ILSpy/TreeNodes/Analyzer/AnalyzedEventFiredByTreeNode.cs diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 8c90134d6..b3ad7a9be 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -144,6 +144,7 @@ + diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedEventFiredByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedEventFiredByTreeNode.cs new file mode 100644 index 000000000..89e892d12 --- /dev/null +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedEventFiredByTreeNode.cs @@ -0,0 +1,144 @@ +// 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. + +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using ICSharpCode.TreeView; +using Mono.Cecil; +using Mono.Cecil.Cil; + +namespace ICSharpCode.ILSpy.TreeNodes.Analyzer +{ + internal sealed class AnalyzedEventFiredByTreeNode : AnalyzerTreeNode + { + private readonly EventDefinition analyzedEvent; + private readonly FieldDefinition eventBackingField; + private readonly MethodDefinition eventFiringMethod; + + private readonly ThreadingSupport threading; + private ConcurrentDictionary foundMethods; + + public AnalyzedEventFiredByTreeNode(EventDefinition analyzedEvent) + { + if (analyzedEvent == null) + throw new ArgumentNullException("analyzedEvent"); + + this.analyzedEvent = analyzedEvent; + this.threading = new ThreadingSupport(); + this.LazyLoading = true; + + this.eventBackingField = analyzedEvent.DeclaringType.Fields.First( + fd => (fd.Name == analyzedEvent.Name || fd.Name == (analyzedEvent.Name + "Event")) && + fd.FieldType.FullName == analyzedEvent.EventType.FullName); + this.eventFiringMethod = analyzedEvent.EventType.Resolve().Methods.First(md => md.Name == "Invoke"); + } + + public override object Text + { + get { return "Raised By"; } + } + + public override object Icon + { + get { return Images.Search; } + } + + protected override void LoadChildren() + { + threading.LoadChildren(this, FetchChildren); + } + + protected override void OnCollapsing() + { + if (threading.IsRunning) { + this.LazyLoading = true; + threading.Cancel(); + this.Children.Clear(); + } + } + + private IEnumerable FetchChildren(CancellationToken ct) + { + foundMethods = new ConcurrentDictionary(); + + foreach (var child in FindReferencesInType()) { + yield return child; + } + + foundMethods = null; + } + + private IEnumerable FindReferencesInType() + { + foreach (MethodDefinition method in analyzedEvent.DeclaringType.Methods) { + bool readBackingField = false; + bool found = false; + if (!method.HasBody) + continue; + foreach (Instruction instr in method.Body.Instructions) { + Code code = instr.OpCode.Code; + if (code == Code.Ldfld || code == Code.Ldflda) { + FieldReference fr = instr.Operand as FieldReference; + if (fr != null && fr.Name == eventBackingField.Name && fr == eventBackingField) { + readBackingField = true; + } + } + if (readBackingField && (code == Code.Callvirt || code == Code.Call)) { + MethodReference mr = instr.Operand as MethodReference; + if (mr != null && mr.Name == eventFiringMethod.Name && mr.Resolve() == eventFiringMethod) { + found = true; + break; + } + } + } + + method.Body = null; + + if (found) { + MethodDefinition codeLocation = this.Language.GetOriginalCodeLocation(method) as MethodDefinition; + if (codeLocation != null && !HasAlreadyBeenFound(codeLocation)) { + yield return new AnalyzedMethodTreeNode(codeLocation); + } + } + } + } + + private bool HasAlreadyBeenFound(MethodDefinition method) + { + return !foundMethods.TryAdd(method, 0); + } + + + public static bool CanShow(EventDefinition ev) + { + var fieldName = ev.Name; + var vbStyleFieldName = fieldName + "Event"; + var fieldType = ev.EventType; + + foreach (var fd in ev.DeclaringType.Fields) { + if (fd.Name == fieldName || fd.Name == vbStyleFieldName) + if (fd.FieldType.FullName == fieldType.FullName) + return true; + } + return false; + } + } +} diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs index 89903abd4..84a937942 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs @@ -59,13 +59,19 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { if (analyzedEvent.AddMethod != null) this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.AddMethod, "add")); + if (analyzedEvent.RemoveMethod != null) this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.RemoveMethod, "remove")); + foreach (var accessor in analyzedEvent.OtherMethods) this.Children.Add(new AnalyzedEventAccessorTreeNode(accessor, null)); + if (AnalyzedEventFiredByTreeNode.CanShow(analyzedEvent)) + this.Children.Add(new AnalyzedEventFiredByTreeNode(analyzedEvent)); + if (AnalyzedEventOverridesTreeNode.CanShow(analyzedEvent)) this.Children.Add(new AnalyzedEventOverridesTreeNode(analyzedEvent)); + if (AnalyzedInterfaceEventImplementedByTreeNode.CanShow(analyzedEvent)) this.Children.Add(new AnalyzedInterfaceEventImplementedByTreeNode(analyzedEvent)); } From 5d7ff43a8473191cf41fe25e9bb70105f365319b Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Tue, 24 May 2011 15:29:22 +1000 Subject: [PATCH 11/16] Analyzer: code refactoring in event raised-by analyzer. --- .../Analyzer/AnalyzedEventFiredByTreeNode.cs | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/ILSpy/TreeNodes/Analyzer/AnalyzedEventFiredByTreeNode.cs b/ILSpy/TreeNodes/Analyzer/AnalyzedEventFiredByTreeNode.cs index 89e892d12..02320cc09 100644 --- a/ILSpy/TreeNodes/Analyzer/AnalyzedEventFiredByTreeNode.cs +++ b/ILSpy/TreeNodes/Analyzer/AnalyzedEventFiredByTreeNode.cs @@ -45,9 +45,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer this.threading = new ThreadingSupport(); this.LazyLoading = true; - this.eventBackingField = analyzedEvent.DeclaringType.Fields.First( - fd => (fd.Name == analyzedEvent.Name || fd.Name == (analyzedEvent.Name + "Event")) && - fd.FieldType.FullName == analyzedEvent.EventType.FullName); + this.eventBackingField = GetBackingField(analyzedEvent); this.eventFiringMethod = analyzedEvent.EventType.Resolve().Methods.First(md => md.Name == "Invoke"); } @@ -79,16 +77,20 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer { foundMethods = new ConcurrentDictionary(); - foreach (var child in FindReferencesInType()) { + foreach (var child in FindReferencesInType(analyzedEvent.DeclaringType)) { yield return child; } foundMethods = null; } - private IEnumerable FindReferencesInType() + private IEnumerable FindReferencesInType(TypeDefinition type) { - foreach (MethodDefinition method in analyzedEvent.DeclaringType.Methods) { + // HACK: in lieu of proper flow analysis, I'm going to use a simple heuristic + // If the method accesses the event's backing field, and calls invoke on a delegate + // with the same signature, then it is (most likely) raise the given event. + + foreach (MethodDefinition method in type.Methods) { bool readBackingField = false; bool found = false; if (!method.HasBody) @@ -126,8 +128,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer return !foundMethods.TryAdd(method, 0); } - - public static bool CanShow(EventDefinition ev) + // HACK: we should probably examine add/remove methods to determine this + private static FieldDefinition GetBackingField(EventDefinition ev) { var fieldName = ev.Name; var vbStyleFieldName = fieldName + "Event"; @@ -136,9 +138,16 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer foreach (var fd in ev.DeclaringType.Fields) { if (fd.Name == fieldName || fd.Name == vbStyleFieldName) if (fd.FieldType.FullName == fieldType.FullName) - return true; + return fd; } - return false; + + return null; + } + + + public static bool CanShow(EventDefinition ev) + { + return GetBackingField(ev) != null; } } } From 6fcc05af6833d84e8d5de3bb6d293c015726ff82 Mon Sep 17 00:00:00 2001 From: Ed Harvey Date: Thu, 26 May 2011 08:37:34 +1000 Subject: [PATCH 12/16] Split out ImageResourceEntryNode, and add support for cursor resources. --- .../ResourceNodes/CursorResourceEntryNode.cs | 95 +++++++++++++++++++ .../ResourceNodes/ImageResourceEntryNode.cs | 87 +++++++++++++++++ .../ResourceNodes/ResourceEntryNode.cs | 59 +----------- 3 files changed, 183 insertions(+), 58 deletions(-) create mode 100644 ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs create mode 100644 ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs diff --git a/ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs new file mode 100644 index 000000000..3a5b41b75 --- /dev/null +++ b/ILSpy/TreeNodes/ResourceNodes/CursorResourceEntryNode.cs @@ -0,0 +1,95 @@ +// 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. + +using System; +using System.ComponentModel.Composition; +using System.IO; +using System.Windows.Controls; +using System.Windows.Media.Imaging; +using ICSharpCode.ILSpy.TextView; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.TreeNodes +{ + [Export(typeof(IResourceNodeFactory))] + sealed class CursorResourceNodeFactory : IResourceNodeFactory + { + static readonly string[] imageFileExtensions = { ".cur" }; + + public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) + { + EmbeddedResource er = resource as EmbeddedResource; + if (er != null) { + return CreateNode(er.Name, er.GetResourceStream()); + } + return null; + } + + public ILSpyTreeNode CreateNode(string key, Stream data) + { + foreach (string fileExt in imageFileExtensions) { + if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) + return new CursorResourceEntryNode(key, data); + } + return null; + } + } + + sealed class CursorResourceEntryNode : ResourceEntryNode + { + public CursorResourceEntryNode(string key, Stream data) + : base(key, data) + { + } + + public override object Icon + { + get { return Images.ResourceImage; } + } + + internal override bool View(DecompilerTextView textView) + { + try { + AvalonEditTextOutput output = new AvalonEditTextOutput(); + Data.Position = 0; + BitmapImage image = new BitmapImage(); + + //HACK: windows imaging does not understand that .cur files have the same layout as .ico + // so load to data, and modify the ResourceType in the header to make look like an icon... + byte[] curData = ((MemoryStream)Data).ToArray(); + curData[2] = 1; + using (Stream stream = new MemoryStream(curData)) { + image.BeginInit(); + image.StreamSource = stream; + image.EndInit(); + } + + output.AddUIElement(() => new Image { Source = image }); + output.WriteLine(); + output.AddButton(Images.Save, "Save", delegate { + Save(null); + }); + textView.ShowNode(output, this, null); + return true; + } + catch (Exception) { + return false; + } + } + } +} diff --git a/ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs new file mode 100644 index 000000000..b333378ab --- /dev/null +++ b/ILSpy/TreeNodes/ResourceNodes/ImageResourceEntryNode.cs @@ -0,0 +1,87 @@ +// 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. + +using System; +using System.ComponentModel.Composition; +using System.IO; +using System.Windows.Controls; +using System.Windows.Media.Imaging; +using ICSharpCode.ILSpy.TextView; +using Mono.Cecil; + +namespace ICSharpCode.ILSpy.TreeNodes +{ + [Export(typeof(IResourceNodeFactory))] + sealed class ImageResourceNodeFactory : IResourceNodeFactory + { + static readonly string[] imageFileExtensions = { ".png", ".gif", ".bmp", ".jpg", ".ico" }; + + public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) + { + EmbeddedResource er = resource as EmbeddedResource; + if (er != null) { + return CreateNode(er.Name, er.GetResourceStream()); + } + return null; + } + + public ILSpyTreeNode CreateNode(string key, Stream data) + { + foreach (string fileExt in imageFileExtensions) { + if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) + return new ImageResourceEntryNode(key, data); + } + return null; + } + } + + sealed class ImageResourceEntryNode : ResourceEntryNode + { + public ImageResourceEntryNode(string key, Stream data) + : base(key, data) + { + } + + public override object Icon + { + get { return Images.ResourceImage; } + } + + internal override bool View(DecompilerTextView textView) + { + try { + AvalonEditTextOutput output = new AvalonEditTextOutput(); + Data.Position = 0; + BitmapImage image = new BitmapImage(); + image.BeginInit(); + image.StreamSource = Data; + image.EndInit(); + output.AddUIElement(() => new Image { Source = image }); + output.WriteLine(); + output.AddButton(Images.Save, "Save", delegate { + Save(null); + }); + textView.ShowNode(output, this, null); + return true; + } + catch (Exception) { + return false; + } + } + } +} diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs index e4b165680..7a077da2d 100644 --- a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs @@ -91,61 +91,4 @@ namespace ICSharpCode.ILSpy.TreeNodes return true; } } - - [Export(typeof(IResourceNodeFactory))] - sealed class ImageResourceNodeFactory : IResourceNodeFactory - { - static readonly string[] imageFileExtensions = { ".png", ".gif", ".bmp", ".jpg", ".ico" }; - - public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) - { - EmbeddedResource er = resource as EmbeddedResource; - if (er != null) { - return CreateNode(er.Name, er.GetResourceStream()); - } - return null; - } - - public ILSpyTreeNode CreateNode(string key, Stream data) - { - foreach (string fileExt in imageFileExtensions) { - if (key.EndsWith(fileExt, StringComparison.OrdinalIgnoreCase)) - return new ImageResourceEntryNode(key, data); - } - return null; - } - } - - sealed class ImageResourceEntryNode : ResourceEntryNode - { - public ImageResourceEntryNode(string key, Stream data) - : base(key, data) - { - } - - public override object Icon - { - get { return Images.ResourceImage; } - } - - internal override bool View(DecompilerTextView textView) - { - try { - AvalonEditTextOutput output = new AvalonEditTextOutput(); - Data.Position = 0; - BitmapImage image = new BitmapImage(); - image.BeginInit(); - image.StreamSource = Data; - image.EndInit(); - output.AddUIElement(() => new Image { Source = image }); - output.WriteLine(); - output.AddButton(Images.Save, "Save", delegate { Save(null); }); - textView.ShowNode(output, this, null); - return true; - } - catch (Exception) { - return false; - } - } - } -} +} \ No newline at end of file From f1a34c6a31e18af6e85ba88cf1d9177d9983e557 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 25 May 2011 22:28:45 +0200 Subject: [PATCH 13/16] Fix #202: Decompilation of multiple catch clauses sharing the same variable name --- .../ILAst/ILAstOptimizer.cs | 27 ++++++++++++++++--- .../ILAst/PeepholeTransform.cs | 4 +-- .../Tests/ExceptionHandling.cs | 20 ++++++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index ef6ab4e54..2bb2f21df 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -575,16 +575,35 @@ namespace ICSharpCode.Decompiler.ILAst // This ensures that a single IL variable is a single C# variable (gets assigned only one name) // The DeclareVariables transformation might then split up the C# variable again if it is used indendently in two separate scopes. Dictionary dict = new Dictionary(); - foreach (ILExpression expr in method.GetSelfAndChildrenRecursive()) { - ILVariable v = expr.Operand as ILVariable; - if (v != null && v.OriginalVariable != null) { + ReplaceVariables( + method, + delegate(ILVariable v) { ILVariable combinedVariable; if (!dict.TryGetValue(v.OriginalVariable, out combinedVariable)) { dict.Add(v.OriginalVariable, v); combinedVariable = v; } - expr.Operand = combinedVariable; + return combinedVariable; + }); + } + + public static void ReplaceVariables(ILNode node, Func variableMapping) + { + ILExpression expr = node as ILExpression; + if (expr != null) { + ILVariable v = expr.Operand as ILVariable; + if (v != null) + expr.Operand = variableMapping(v); + foreach (ILExpression child in expr.Arguments) + ReplaceVariables(child, variableMapping); + } else { + var catchBlock = node as ILTryCatchBlock.CatchBlock; + if (catchBlock != null && catchBlock.ExceptionVariable != null) { + catchBlock.ExceptionVariable = variableMapping(catchBlock.ExceptionVariable); } + + foreach (ILNode child in node.GetChildren()) + ReplaceVariables(child, variableMapping); } } diff --git a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs index f9e596514..88900a73b 100644 --- a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs +++ b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs @@ -523,8 +523,8 @@ namespace ICSharpCode.Decompiler.ILAst if (recombineVariable) { // Split local variable, unsplit these two instances - foreach (var ilExpression in method.GetSelfAndChildrenRecursive(expression => expression.Operand == nextExpr.Operand)) - ilExpression.Operand = exprInit.Operand; + // replace nextExpr.Operand with exprInit.Operand + ReplaceVariables(method, oldVar => oldVar == nextExpr.Operand ? (ILVariable)exprInit.Operand : oldVar); } switch (loadInstruction) { diff --git a/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs b/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs index 45b5d72ca..0db35e357 100644 --- a/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs +++ b/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs @@ -105,4 +105,24 @@ public class ExceptionHandling cancellationTokenSource = new CancellationTokenSource(); } } + + public void TwoCatchBlocksWithSameVariable() + { + try + { + Console.WriteLine("Try1"); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + try + { + Console.WriteLine("Try2"); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + } + } } From 67fcd4ef7de0ad13ef1c40c09e255158bf7926c8 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 26 May 2011 19:26:38 +0200 Subject: [PATCH 14/16] Fix NullReferenceException in ILAstOptimizer.RecombineVariables --- ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index 2bb2f21df..c4447f4d4 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -578,6 +578,8 @@ namespace ICSharpCode.Decompiler.ILAst ReplaceVariables( method, delegate(ILVariable v) { + if (v.OriginalVariable == null) + return v; ILVariable combinedVariable; if (!dict.TryGetValue(v.OriginalVariable, out combinedVariable)) { dict.Add(v.OriginalVariable, v); From c2eb91797c1cae50bc65fc020e08d6401362447e Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 27 May 2011 13:42:36 +0200 Subject: [PATCH 15/16] Make file extension comparison case-insensitive. --- ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs b/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs index 004e26272..ce2f1e1d4 100644 --- a/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs +++ b/ILSpy/TreeNodes/ResourceNodes/XmlResourceNode.cs @@ -64,11 +64,11 @@ namespace ICSharpCode.ILSpy.Xaml get { string text = (string)Text; - if (text.EndsWith(".xml")) + if (text.EndsWith(".xml", StringComparison.OrdinalIgnoreCase)) return Images.ResourceXml; - else if (text.EndsWith(".xsd")) + else if (text.EndsWith(".xsd", StringComparison.OrdinalIgnoreCase)) return Images.ResourceXsd; - else if (text.EndsWith(".xslt")) + else if (text.EndsWith(".xslt", StringComparison.OrdinalIgnoreCase)) return Images.ResourceXslt; else return Images.Resource; From e8b6e3d8083c331a6db4c78f982311143b6484e6 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Fri, 27 May 2011 13:44:45 +0200 Subject: [PATCH 16/16] Annotate anonymous methods/lambdas with the MethodDefinition representing the lambda body. --- ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs index 85ac9da1e..0e431e3f8 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs @@ -136,6 +136,9 @@ namespace ICSharpCode.Decompiler.Ast.Transforms // Create AnonymousMethodExpression and prepare parameters AnonymousMethodExpression ame = new AnonymousMethodExpression(); + ame.CopyAnnotationsFrom(objectCreateExpression); // copy ILRanges etc. + ame.RemoveAnnotations(); // remove reference to delegate ctor + ame.AddAnnotation(method); // add reference to anonymous method ame.Parameters.AddRange(AstBuilder.MakeParameters(method, isLambda: true)); ame.HasParameterList = true; @@ -180,6 +183,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms } if (isLambda) { LambdaExpression lambda = new LambdaExpression(); + lambda.CopyAnnotationsFrom(ame); ame.Parameters.MoveTo(lambda.Parameters); Expression returnExpr = ((ReturnStatement)body.Statements.Single()).Expression; returnExpr.Remove();