diff --git a/ICSharpCode.Decompiler/Disassembler/ILStructure.cs b/ICSharpCode.Decompiler/Disassembler/ILStructure.cs index 52d359a2a..56f35792b 100644 --- a/ICSharpCode.Decompiler/Disassembler/ILStructure.cs +++ b/ICSharpCode.Decompiler/Disassembler/ILStructure.cs @@ -92,7 +92,7 @@ namespace ICSharpCode.Decompiler.Disassembler AddNestedStructure(new ILStructure(ILStructureType.Try, eh.TryStart.Offset, eh.TryEnd.Offset, eh)); if (eh.HandlerType == ExceptionHandlerType.Filter) AddNestedStructure(new ILStructure(ILStructureType.Filter, eh.FilterStart.Offset, eh.FilterEnd.Offset, eh)); - AddNestedStructure(new ILStructure(ILStructureType.Handler, eh.HandlerStart.Offset, eh.HandlerEnd.Offset, eh)); + AddNestedStructure(new ILStructure(ILStructureType.Handler, eh.HandlerStart.Offset, eh.HandlerEnd == null ? body.CodeSize : eh.HandlerEnd.Offset, eh)); } // Very simple loop detection: look for backward branches List> allBranches = FindAllBranches(body); diff --git a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs index ea228e014..51656fc1a 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs @@ -567,8 +567,9 @@ namespace Decompiler int startIndex; for (startIndex = 0; body[startIndex].Offset != eh.HandlerStart.Offset; startIndex++); int endInclusiveIndex; - // Note that the end(exclusiove) instruction may not necessarly be in our body - for (endInclusiveIndex = 0; body[endInclusiveIndex].Next.Offset != eh.HandlerEnd.Offset; endInclusiveIndex++); + if (eh.HandlerEnd == null) endInclusiveIndex = body.Count - 1; + // Note that the end(exclusive) instruction may not necessarly be in our body + else for (endInclusiveIndex = 0; body[endInclusiveIndex].Next.Offset != eh.HandlerEnd.Offset; endInclusiveIndex++); int count = 1 + endInclusiveIndex - startIndex; HashSet nestedEHs = new HashSet(ehs.Where(e => (eh.HandlerStart.Offset <= e.TryStart.Offset && e.TryEnd.Offset < eh.HandlerEnd.Offset) || (eh.HandlerStart.Offset < e.TryStart.Offset && e.TryEnd.Offset <= eh.HandlerEnd.Offset))); ehs.ExceptWith(nestedEHs); diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs index 6c79b565e..e7ed4a7dd 100644 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs @@ -286,7 +286,9 @@ namespace Decompiler case ILCode.Ldvirtftn: return typeSystem.IntPtr; case ILCode.Ldc_I4: - return (IsIntegerOrEnum(expectedType) || IsBoolean(expectedType)) ? expectedType : typeSystem.Int32; + if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1)) + return typeSystem.Boolean; + return IsIntegerOrEnum(expectedType) ? expectedType : typeSystem.Int32; case ILCode.Ldc_I8: return (IsIntegerOrEnum(expectedType)) ? expectedType : typeSystem.Int64; case ILCode.Ldc_R4: @@ -561,7 +563,7 @@ namespace Decompiler } else { left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred); left.InferredType = DoInferTypeForExpression(left, left.ExpectedType); - right.InferredType = DoInferTypeForExpression(left, right.ExpectedType); + right.InferredType = DoInferTypeForExpression(right, right.ExpectedType); return left.ExpectedType; } } diff --git a/ICSharpCode.Decompiler/Tests/BooleanConsumedAsInteger.il b/ICSharpCode.Decompiler/Tests/BooleanConsumedAsInteger.il new file mode 100644 index 000000000..9e3000279 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/BooleanConsumedAsInteger.il @@ -0,0 +1,59 @@ +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) + .ver 4:0:0:0 +} +.assembly BooleanConsumedAsInteger +{ + .hash algorithm 0x00008004 + .ver 1:0:0:0 +} +.module BooleanConsumedAsInteger.exe +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000003 // ILONLY 32BITREQUIRED + +.class private auto ansi beforefieldinit BooleanConsumedAsInteger.Program extends [mscorlib]System.Object +{ + .method public hidebysig static void Main(string[] args) cil managed + { + .entrypoint + .maxstack 8 + + ret + } + + .method public hidebysig static int32 ReturnBoolAsInt() cil managed + { + ldnull + ldnull + call bool [mscorlib] System.Object::Equals(object, object) + ret + } + + .method public hidebysig static int32 BitwiseOperationOnBool() cil managed + { + ldnull + ldnull + call bool [mscorlib] System.Object::Equals(object, object) + ldc.i4 255 + and + ret + } + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method Program::.ctor + +} // end of class StackTests.Program + + +// ============================================================= diff --git a/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs b/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs new file mode 100644 index 000000000..21b259126 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs @@ -0,0 +1,25 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; + +public class ExceptionHandling +{ + public void MethodEndingWithEndFinally() + { + try { + throw null; + } finally { + Console.WriteLine(); + } + } + + public void MethodEndingWithRethrow() + { + try { + throw null; + } catch { + throw; + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 7206c2201..e6d805fb5 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -49,6 +49,7 @@ + @@ -64,5 +65,12 @@ ICSharpCode.Decompiler + + + + + + + \ No newline at end of file diff --git a/ILSpy/CSharpLanguage.cs b/ILSpy/CSharpLanguage.cs index ca17d220c..7ff152475 100644 --- a/ILSpy/CSharpLanguage.cs +++ b/ILSpy/CSharpLanguage.cs @@ -17,12 +17,15 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Threading; +using System.Resources; using System.Threading.Tasks; +using System.Xaml; using System.Xml; + using Decompiler; using Decompiler.Transforms; using ICSharpCode.Decompiler; @@ -115,7 +118,9 @@ namespace ICSharpCode.ILSpy { if (options.FullDecompilation) { if (options.SaveAsProjectDirectory != null) { - var files = WriteFilesInProject(assembly, options); + HashSet directories = new HashSet(StringComparer.OrdinalIgnoreCase); + var files = WriteCodeFilesInProject(assembly, options, directories).ToList(); + files.AddRange(WriteResourceFilesInProject(assembly, fileName, options, directories)); WriteProjectFile(new TextOutputWriter(output), files, assembly.MainModule); } else { foreach (TypeDefinition type in assembly.MainModule.Types) { @@ -130,7 +135,8 @@ namespace ICSharpCode.ILSpy } } - void WriteProjectFile(TextWriter writer, IEnumerable files, ModuleDefinition module) + #region WriteProjectFile + void WriteProjectFile(TextWriter writer, IEnumerable> files, ModuleDefinition module) { const string ns = "http://schemas.microsoft.com/developer/msbuild/2003"; string platformName; @@ -236,13 +242,15 @@ namespace ICSharpCode.ILSpy } w.WriteEndElement(); // (References) - w.WriteStartElement("ItemGroup"); // Code - foreach (string file in files.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)) { - w.WriteStartElement("Compile"); - w.WriteAttributeString("Include", file); + foreach (IGrouping gr in (from f in files group f.Item2 by f.Item1 into g orderby g.Key select g)) { + w.WriteStartElement("ItemGroup"); + foreach (string file in gr.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)) { + w.WriteStartElement(gr.Key); + w.WriteAttributeString("Include", file); + w.WriteEndElement(); + } w.WriteEndElement(); } - w.WriteEndElement(); w.WriteStartElement("Import"); w.WriteAttributeString("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets"); @@ -251,8 +259,10 @@ namespace ICSharpCode.ILSpy w.WriteEndDocument(); } } + #endregion - IEnumerable WriteFilesInProject(AssemblyDefinition assembly, DecompilationOptions options) + #region WriteCodeFilesInProject + IEnumerable> WriteCodeFilesInProject(AssemblyDefinition assembly, DecompilationOptions options, HashSet directories) { var files = assembly.MainModule.Types.Where(t => t.Name != "").GroupBy( delegate (TypeDefinition type) { @@ -261,11 +271,11 @@ namespace ICSharpCode.ILSpy return file; } else { string dir = TextView.DecompilerTextView.CleanUpName(type.Namespace); - Directory.CreateDirectory(Path.Combine(options.SaveAsProjectDirectory, dir)); + if (directories.Add(dir)) + Directory.CreateDirectory(Path.Combine(options.SaveAsProjectDirectory, dir)); return Path.Combine(dir, file); } }, StringComparer.OrdinalIgnoreCase).ToList(); - AstMethodBodyBuilder.ClearUnhandledOpcodes(); Parallel.ForEach( files, @@ -279,8 +289,83 @@ namespace ICSharpCode.ILSpy } }); AstMethodBodyBuilder.PrintNumberOfUnhandledOpcodes(); - return files.Select(f => f.Key); + return files.Select(f => Tuple.Create("Compile", f.Key)); + } + #endregion + + #region WriteResourceFilesInProject + IEnumerable> WriteResourceFilesInProject(AssemblyDefinition assembly, string assemblyFileName, DecompilationOptions options, HashSet directories) + { + AppDomain bamlDecompilerAppDomain = null; + try { + foreach (EmbeddedResource r in assembly.MainModule.Resources.OfType()) { + string fileName; + Stream s = r.GetResourceStream(); + s.Position = 0; + if (r.Name.EndsWith(".g.resources", StringComparison.OrdinalIgnoreCase)) { + IEnumerable rs = null; + try { + rs = new ResourceSet(s).Cast(); + } catch (ArgumentException) { + } + if (rs != null && rs.All(e => e.Value is Stream)) { + foreach (var pair in rs) { + fileName = Path.Combine(((string)pair.Key).Split('/').Select(p => TextView.DecompilerTextView.CleanUpName(p)).ToArray()); + string dirName = Path.GetDirectoryName(fileName); + if (!string.IsNullOrEmpty(dirName) && directories.Add(dirName)) { + Directory.CreateDirectory(Path.Combine(options.SaveAsProjectDirectory, dirName)); + } + Stream entryStream = (Stream)pair.Value; + entryStream.Position = 0; + if (fileName.EndsWith(".baml", StringComparison.OrdinalIgnoreCase)) { + MemoryStream ms = new MemoryStream(); + entryStream.CopyTo(ms); + BamlDecompiler decompiler = TreeNodes.ResourceEntryNode.CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, assemblyFileName); + string xaml = null; + try { + xaml = decompiler.DecompileBaml(ms, assemblyFileName); + } catch (XamlXmlWriterException) {} // ignore XAML writer exceptions + if (xaml != null) { + File.WriteAllText(Path.Combine(options.SaveAsProjectDirectory, Path.ChangeExtension(fileName, ".xaml")), xaml); + yield return Tuple.Create("Page", Path.ChangeExtension(fileName, ".xaml")); + continue; + } + } + using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) { + entryStream.CopyTo(fs); + } + yield return Tuple.Create("Resource", fileName); + } + continue; + } + } + fileName = GetFileNameForResource(r.Name, directories); + using (FileStream fs = new FileStream(Path.Combine(options.SaveAsProjectDirectory, fileName), FileMode.Create, FileAccess.Write)) { + s.CopyTo(fs); + } + yield return Tuple.Create("EmbeddedResource", fileName); + } + } finally { + if (bamlDecompilerAppDomain != null) + AppDomain.Unload(bamlDecompilerAppDomain); + } + } + + string GetFileNameForResource(string fullName, HashSet directories) + { + string[] splitName = fullName.Split('.'); + string fileName = TextView.DecompilerTextView.CleanUpName(fullName); + for (int i = splitName.Length - 1; i > 0; i--) { + string ns = string.Join(".", splitName, 0, i); + if (directories.Contains(ns)) { + string name = string.Join(".", splitName, i, splitName.Length - i); + fileName = Path.Combine(ns, TextView.DecompilerTextView.CleanUpName(name)); + break; + } + } + return fileName; } + #endregion AstBuilder CreateAstBuilder(DecompilationOptions options, TypeDefinition currentType) { diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index c77bcb2b7..8029fc21b 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -283,21 +283,31 @@ namespace ICSharpCode.ILSpy.TextView Thread thread = new Thread(new ThreadStart( delegate { - try { - AvalonEditTextOutput textOutput = new AvalonEditTextOutput(); - textOutput.LengthLimit = outputLengthLimit; - DecompileNodes(context, textOutput); - textOutput.PrepareDocument(); - tcs.SetResult(textOutput); - #if DEBUG - } catch (AggregateException ex) { - tcs.SetException(ex); - } catch (OperationCanceledException ex) { - tcs.SetException(ex); - #else - } catch (Exception ex) { - tcs.SetException(ex); + #if DEBUG + if (Debugger.IsAttached) { + try { + AvalonEditTextOutput textOutput = new AvalonEditTextOutput(); + textOutput.LengthLimit = outputLengthLimit; + DecompileNodes(context, textOutput); + textOutput.PrepareDocument(); + tcs.SetResult(textOutput); + } catch (AggregateException ex) { + tcs.SetException(ex); + } catch (OperationCanceledException ex) { + tcs.SetException(ex); + } + } else #endif + { + try { + AvalonEditTextOutput textOutput = new AvalonEditTextOutput(); + textOutput.LengthLimit = outputLengthLimit; + DecompileNodes(context, textOutput); + textOutput.PrepareDocument(); + tcs.SetResult(textOutput); + } catch (Exception ex) { + tcs.SetException(ex); + } } })); thread.Start(); diff --git a/ILSpy/TreeNodes/ResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceEntryNode.cs index a167a916d..dc982bf00 100644 --- a/ILSpy/TreeNodes/ResourceEntryNode.cs +++ b/ILSpy/TreeNodes/ResourceEntryNode.cs @@ -86,24 +86,36 @@ namespace ICSharpCode.ILSpy.TreeNodes { var asm = this.Ancestors().OfType().FirstOrDefault().LoadedAssembly; - // Construct and initialize settings for a second AppDomain. - AppDomainSetup bamlDecompilerAppDomainSetup = new AppDomainSetup(); - bamlDecompilerAppDomainSetup.ApplicationBase = "file:///" + Path.GetDirectoryName(asm.FileName); - bamlDecompilerAppDomainSetup.DisallowBindingRedirects = false; - bamlDecompilerAppDomainSetup.DisallowCodeDownload = true; - bamlDecompilerAppDomainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile; + AppDomain bamlDecompilerAppDomain = null; + try { + BamlDecompiler decompiler = CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, asm.FileName); + + MemoryStream bamlStream = new MemoryStream(); + value.Position = 0; + value.CopyTo(bamlStream); + + output.Write(decompiler.DecompileBaml(bamlStream, asm.FileName)); + 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 bamlDecompilerAppDomain = AppDomain.CreateDomain("BamlDecompiler AD", null, bamlDecompilerAppDomainSetup); - - BamlDecompiler decompiler = (BamlDecompiler)bamlDecompilerAppDomain.CreateInstanceFromAndUnwrap(typeof(BamlDecompiler).Assembly.Location, typeof(BamlDecompiler).FullName); - - MemoryStream bamlStream = new MemoryStream(); - value.Position = 0; - value.CopyTo(bamlStream); - - output.Write(decompiler.DecompileBaml(bamlStream, asm.FileName)); - return true; + // Create the second AppDomain. + appDomain = AppDomain.CreateDomain("BamlDecompiler AD", null, bamlDecompilerAppDomainSetup); + } + return (BamlDecompiler)appDomain.CreateInstanceFromAndUnwrap(typeof(BamlDecompiler).Assembly.Location, typeof(BamlDecompiler).FullName); } public override bool Save(DecompilerTextView textView) diff --git a/ILSpy/TreeNodes/ResourceListTreeNode.cs b/ILSpy/TreeNodes/ResourceListTreeNode.cs index f3d3ed5ca..44ae1e2c5 100644 --- a/ILSpy/TreeNodes/ResourceListTreeNode.cs +++ b/ILSpy/TreeNodes/ResourceListTreeNode.cs @@ -156,9 +156,10 @@ namespace ICSharpCode.ILSpy.TreeNodes if (er != null) { try { Stream s = er.GetResourceStream(); + s.Position = 0; if (er.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) { - ResourceSet set = new ResourceSet(s); - foreach (DictionaryEntry entry in set.Cast().OrderBy(e => e.Key.ToString())) { + ResourceReader reader = new ResourceReader(s); + foreach (DictionaryEntry entry in reader.Cast().OrderBy(e => e.Key.ToString())) { if (entry.Value is Stream) Children.Add(new ResourceEntryNode(entry.Key.ToString(), (Stream)entry.Value)); } diff --git a/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index a0aae81d2..fb6ae2c31 100644 --- a/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -342,16 +342,6 @@ - - - - - - - {D68133BD-1E63-496E-9EDE-4FBDBF77B486} - Mono.Cecil - - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}