From 12a0bb330d0c8400476aadafbe50e8da06d30fbf Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 16 Feb 2011 16:58:48 +0100 Subject: [PATCH 1/9] If the decompiler crashes: Show name of the decompiled method in the exception message. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 4 +- .../Ast/AstMethodBodyBuilder.cs | 12 +++- ICSharpCode.Decompiler/DecompilerException.cs | 27 ++++++++ .../ICSharpCode.Decompiler.csproj | 1 + ILSpy/CSharpLanguage.cs | 14 ++++ ILSpy/MainWindow.xaml.cs | 2 +- ILSpy/TextView/DecompilerTextView.cs | 67 ++++++++++++------- 7 files changed, 98 insertions(+), 29 deletions(-) create mode 100644 ICSharpCode.Decompiler/DecompilerException.cs diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 5116658a5..db60e45f2 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -337,6 +337,8 @@ namespace Decompiler Modifiers ConvertModifiers(MethodDefinition methodDef) { + if (methodDef == null) + return Modifiers.None; Modifiers modifiers = Modifiers.None; if (methodDef.IsPrivate) modifiers |= Modifiers.Private; @@ -431,7 +433,7 @@ namespace Decompiler PropertyDeclaration CreateProperty(PropertyDefinition propDef) { PropertyDeclaration astProp = new PropertyDeclaration(); - astProp.Modifiers = ConvertModifiers(propDef.GetMethod); + astProp.Modifiers = ConvertModifiers(propDef.GetMethod ?? propDef.SetMethod); astProp.Name = propDef.Name; astProp.ReturnType = ConvertType(propDef.PropertyType, propDef); if (propDef.GetMethod != null) { diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index 1f131d3b5..b80aa09ac 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -21,7 +21,17 @@ namespace Decompiler { AstMethodBodyBuilder builder = new AstMethodBodyBuilder(); builder.methodDef = methodDef; - return builder.CreateMethodBody(); + if (Debugger.IsAttached) { + return builder.CreateMethodBody(); + } else { + try { + return builder.CreateMethodBody(); + } catch (OperationCanceledException) { + throw; + } catch (Exception ex) { + throw new ICSharpCode.Decompiler.DecompilerException(methodDef, ex); + } + } } static readonly Dictionary typeNameToVariableNameDict = new Dictionary { diff --git a/ICSharpCode.Decompiler/DecompilerException.cs b/ICSharpCode.Decompiler/DecompilerException.cs new file mode 100644 index 000000000..bb5379a6b --- /dev/null +++ b/ICSharpCode.Decompiler/DecompilerException.cs @@ -0,0 +1,27 @@ +// 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; +using System.Runtime.Serialization; +using Mono.Cecil; + +namespace ICSharpCode.Decompiler +{ + /// + /// Desctiption of DecompilerException. + /// + public class DecompilerException : Exception, ISerializable + { + public MethodDefinition DecompiledMethod { get; set; } + + public DecompilerException(MethodDefinition decompiledMethod, Exception innerException) + : base("Error decompiling " + decompiledMethod.FullName, innerException) + { + } + + // This constructor is needed for serialization. + protected DecompilerException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 9beef196d..fdda5b4ab 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -64,6 +64,7 @@ + diff --git a/ILSpy/CSharpLanguage.cs b/ILSpy/CSharpLanguage.cs index 3368f1594..e8800f8b0 100644 --- a/ILSpy/CSharpLanguage.cs +++ b/ILSpy/CSharpLanguage.cs @@ -101,6 +101,20 @@ namespace ICSharpCode.ILSpy codeDomBuilder.GenerateCode(output, transformAbortCondition); } + public override void DecompileAssembly(AssemblyDefinition assembly, string fileName, ITextOutput output, DecompilationOptions options) + { + if (options.FullDecompilation) { + foreach (TypeDefinition type in assembly.MainModule.Types) { + AstBuilder codeDomBuilder = new AstBuilder(); + codeDomBuilder.AddType(type); + codeDomBuilder.GenerateCode(output, transformAbortCondition); + output.WriteLine(); + } + } else { + base.DecompileAssembly(assembly, fileName, output, options); + } + } + public override string TypeToString(TypeReference type, bool includeNamespace, ICustomAttributeProvider typeAttributes) { AstType astType = AstBuilder.ConvertType(type, typeAttributes); diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 9abe7a2a0..7a79cc166 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -397,7 +397,7 @@ namespace ICSharpCode.ILSpy } decompilerTextView.SaveToDisk(sessionSettings.FilterSettings.Language, treeView.GetTopLevelSelection().OfType(), - new DecompilationOptions()); + new DecompilationOptions() { FullDecompilation = true }); } #endregion diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index a652c618c..034fa8da3 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -225,7 +225,7 @@ namespace ICSharpCode.ILSpy.TextView RunWithCancellation( delegate (CancellationToken ct) { // creation of the background task context.Options.CancellationToken = ct; - return RunDecompiler(context, outputLengthLimit); + return DecompileAsync(context, outputLengthLimit); }, delegate (Task task) { // handling the result try { @@ -250,7 +250,7 @@ namespace ICSharpCode.ILSpy.TextView }); } - static Task RunDecompiler(DecompilationContext context, int outputLengthLimit) + static Task DecompileAsync(DecompilationContext context, int outputLengthLimit) { Debug.WriteLine("Start decompilation of {0} tree nodes", context.TreeNodes.Length); @@ -274,10 +274,11 @@ namespace ICSharpCode.ILSpy.TextView } catch (AggregateException ex) { tcs.SetException(ex); } catch (OperationCanceledException ex) { + tcs.SetException(ex); #else } catch (Exception ex) { - #endif tcs.SetException(ex); + #endif } })); thread.Start(); @@ -392,29 +393,7 @@ namespace ICSharpCode.ILSpy.TextView RunWithCancellation( delegate (CancellationToken ct) { context.Options.CancellationToken = ct; - return Task.Factory.StartNew( - delegate { - using (StreamWriter w = new StreamWriter(fileName)) { - try { - DecompileNodes(context, new PlainTextOutput(w)); - } catch (OperationCanceledException) { - w.WriteLine(); - w.WriteLine("Decompiled was cancelled."); - throw; - } - } - AvalonEditTextOutput output = new AvalonEditTextOutput(); - output.WriteLine("Decompilation complete."); - output.WriteLine(); - output.AddButton( - null, "Open Explorer", - delegate { - Process.Start("explorer", "/select,\"" + fileName + "\""); - } - ); - output.WriteLine(); - return output; - }, TaskCreationOptions.LongRunning); + return SaveToDiskAsync(context, fileName); }, delegate (Task task) { try { @@ -433,6 +412,42 @@ namespace ICSharpCode.ILSpy.TextView } }); } + + Task SaveToDiskAsync(DecompilationContext context, string fileName) + { + TaskCompletionSource tcs = new TaskCompletionSource(); + Thread thread = new Thread(new ThreadStart( + delegate { + try { + using (StreamWriter w = new StreamWriter(fileName)) { + try { + DecompileNodes(context, new PlainTextOutput(w)); + } catch (OperationCanceledException) { + w.WriteLine(); + w.WriteLine("Decompiled was cancelled."); + throw; + } + } + AvalonEditTextOutput output = new AvalonEditTextOutput(); + output.WriteLine("Decompilation complete."); + output.WriteLine(); + output.AddButton(null, "Open Explorer", delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); }); + output.WriteLine(); + tcs.SetResult(output); + #if DEBUG + } catch (OperationCanceledException ex) { + tcs.SetException(ex); + } catch (AggregateException ex) { + tcs.SetException(ex); + #else + } catch (Exception ex) { + tcs.SetException(ex); + #endif + } + })); + thread.Start(); + return tcs.Task; + } /// /// Cleans up a node name for use as a file name. From 4b6bd1bd7c34bdfd433ea2ae7233899dcc233ce4 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 16 Feb 2011 17:09:41 +0100 Subject: [PATCH 2/9] Fix crash when decompiling delegate creation of generic method. --- ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs | 4 +++- ICSharpCode.Decompiler/DecompilerException.cs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs index 4f3786120..c2a4f7245 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs @@ -74,10 +74,12 @@ namespace Decompiler.Transforms } } // now transform the identifier into a member reference + var typeArguments = methodIdent.TypeArguments.ToArray(); + methodIdent.TypeArguments = null; MemberReferenceExpression mre = new MemberReferenceExpression { Target = obj, MemberName = methodIdent.Identifier, - TypeArguments = methodIdent.TypeArguments + TypeArguments = typeArguments }; mre.AddAnnotation(method); objectCreateExpression.Arguments = new [] { mre }; diff --git a/ICSharpCode.Decompiler/DecompilerException.cs b/ICSharpCode.Decompiler/DecompilerException.cs index bb5379a6b..c7316f775 100644 --- a/ICSharpCode.Decompiler/DecompilerException.cs +++ b/ICSharpCode.Decompiler/DecompilerException.cs @@ -15,7 +15,7 @@ namespace ICSharpCode.Decompiler public MethodDefinition DecompiledMethod { get; set; } public DecompilerException(MethodDefinition decompiledMethod, Exception innerException) - : base("Error decompiling " + decompiledMethod.FullName, innerException) + : base("Error decompiling " + decompiledMethod.FullName + Environment.NewLine, innerException) { } From 0ede3cf555e9dc381dc73f6a4b4d71cf49dc9e8c Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 16 Feb 2011 17:34:15 +0100 Subject: [PATCH 3/9] Fix TreeFlattener.IndexOf (avoids crash when navigating or loading assemblies while a search filter is active) --- SharpTreeView/TreeFlattener.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpTreeView/TreeFlattener.cs b/SharpTreeView/TreeFlattener.cs index eb6895084..332031dfd 100644 --- a/SharpTreeView/TreeFlattener.cs +++ b/SharpTreeView/TreeFlattener.cs @@ -81,7 +81,7 @@ namespace ICSharpCode.TreeView public int IndexOf(object item) { SharpTreeNode node = item as SharpTreeNode; - if (node != null && node.GetListRoot() == root) { + if (node != null && node.IsVisible && node.GetListRoot() == root) { if (includeRoot) return SharpTreeNode.GetVisibleIndexForNode(node); else From 7a81ab2e1e4dfdb3b698af90f31a49d64d84b768 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 16 Feb 2011 18:40:37 +0100 Subject: [PATCH 4/9] Patch Mono.Cecil to allow safe multi-threaded read access. --- Mono.Cecil/Mono.Cecil/ModuleDefinition.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Mono.Cecil/Mono.Cecil/ModuleDefinition.cs b/Mono.Cecil/Mono.Cecil/ModuleDefinition.cs index 7c793f5a2..ea84209d7 100644 --- a/Mono.Cecil/Mono.Cecil/ModuleDefinition.cs +++ b/Mono.Cecil/Mono.Cecil/ModuleDefinition.cs @@ -757,18 +757,22 @@ namespace Mono.Cecil { { return Read (this, (_, reader) => reader.LookupToken (token)); } + + readonly object module_lock = new object(); internal TRet Read (TItem item, Func read) { - var position = reader.position; - var context = reader.context; + lock (module_lock) { + var position = reader.position; + var context = reader.context; - var ret = read (item, reader); + var ret = read (item, reader); - reader.position = position; - reader.context = context; + reader.position = position; + reader.context = context; - return ret; + return ret; + } } void ProcessDebugHeader () From a460bc65ab02157b0c595e0c5dd500d281aa0eb7 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 16 Feb 2011 18:49:06 +0100 Subject: [PATCH 5/9] Fix order of modifiers. --- .../CSharp/Ast/CSharpModifierToken.cs | 52 +++++++++++-------- .../CSharp/Ast/TypeMembers/AttributedNode.cs | 4 +- 2 files changed, 33 insertions(+), 23 deletions(-) diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs index 3b48cdf59..6b2b12959 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs @@ -25,6 +25,7 @@ // THE SOFTWARE. using System; using System.Collections.Generic; +using System.Linq; namespace ICSharpCode.NRefactory.CSharp { @@ -36,33 +37,40 @@ namespace ICSharpCode.NRefactory.CSharp public Modifiers Modifier { get { return modifier; } set { - modifier = value; - if (!lengthTable.TryGetValue (modifier, out tokenLength)) - throw new InvalidOperationException ("Modifier " + modifier + " is invalid."); + for (int i = 0; i < lengthTable.Count; i++) { + if (lengthTable[i].Key == value) { + this.modifier = value; + this.tokenLength = lengthTable[i].Value; + return; + } + } + throw new ArgumentException ("Modifier " + value + " is invalid."); } } - static Dictionary lengthTable = new Dictionary () { - { Modifiers.Public, "public".Length }, - { Modifiers.Protected, "protected".Length }, - { Modifiers.Private, "private".Length }, - { Modifiers.Internal, "internal".Length }, - { Modifiers.New, "new".Length }, - { Modifiers.Unsafe, "unsafe".Length }, - { Modifiers.Abstract, "abstract".Length }, - { Modifiers.Virtual, "virtual".Length }, - { Modifiers.Sealed, "sealed".Length }, - { Modifiers.Static, "static".Length }, - { Modifiers.Override, "override".Length }, - { Modifiers.Readonly, "readonly".Length }, - { Modifiers.Volatile, "volatile".Length }, - { Modifiers.Extern, "extern".Length }, - { Modifiers.Partial, "partial".Length }, - { Modifiers.Const, "const".Length }, + // Not worth using a dictionary for such few elements. + // This table is sorted in the order that modifiers should be output when generating code. + static readonly List> lengthTable = new List> () { + new KeyValuePair(Modifiers.Public, "public".Length), + new KeyValuePair(Modifiers.Protected, "protected".Length), + new KeyValuePair(Modifiers.Private, "private".Length), + new KeyValuePair(Modifiers.Internal, "internal".Length), + new KeyValuePair(Modifiers.New, "new".Length), + new KeyValuePair(Modifiers.Unsafe, "unsafe".Length), + new KeyValuePair(Modifiers.Abstract, "abstract".Length), + new KeyValuePair(Modifiers.Virtual, "virtual".Length), + new KeyValuePair(Modifiers.Sealed, "sealed".Length), + new KeyValuePair(Modifiers.Static, "static".Length), + new KeyValuePair(Modifiers.Override, "override".Length), + new KeyValuePair(Modifiers.Readonly, "readonly".Length), + new KeyValuePair(Modifiers.Volatile, "volatile".Length), + new KeyValuePair(Modifiers.Extern, "extern".Length), + new KeyValuePair(Modifiers.Partial, "partial".Length), + new KeyValuePair(Modifiers.Const, "const".Length) }; - public static ICollection AllModifiers { - get { return lengthTable.Keys; } + public static IEnumerable AllModifiers { + get { return lengthTable.Select(p => p.Key); } } public CSharpModifierToken (AstLocation location, Modifiers modifier) : base (location, 0) diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs index 99d8af8ec..a2734ae4f 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs @@ -42,7 +42,9 @@ namespace ICSharpCode.NRefactory.CSharp if ((m & newValue) != 0) { if ((m & oldValue) == 0) { // Modifier was added - node.InsertChildAfter(insertionPos, new CSharpModifierToken(AstLocation.Empty, m), ModifierRole); + var newToken = new CSharpModifierToken(AstLocation.Empty, m); + node.InsertChildAfter(insertionPos, newToken, ModifierRole); + insertionPos = newToken; } else { // Modifier already exists insertionPos = node.GetChildrenByRole(ModifierRole).First(t => t.Modifier == m); From c4b63b87c6edee7eceefd9f26325b5732b87e2a4 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 16 Feb 2011 18:52:39 +0100 Subject: [PATCH 6/9] Show values of constants. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index db60e45f2..d3480ca42 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -471,9 +471,16 @@ namespace Decompiler FieldDeclaration CreateField(FieldDefinition fieldDef) { FieldDeclaration astField = new FieldDeclaration(); - astField.AddChild(new VariableInitializer(fieldDef.Name), FieldDeclaration.Roles.Variable); + VariableInitializer initializer = new VariableInitializer(fieldDef.Name); + astField.AddChild(initializer, FieldDeclaration.Roles.Variable); astField.ReturnType = ConvertType(fieldDef.FieldType, fieldDef); astField.Modifiers = ConvertModifiers(fieldDef); + if (fieldDef.HasConstant) { + if (fieldDef.Constant == null) + initializer.Initializer = new NullReferenceExpression(); + else + initializer.Initializer = new PrimitiveExpression(fieldDef.Constant); + } return astField; } From 578a8a83c54ffc1b10a80938406a90f736641659 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 16 Feb 2011 18:53:04 +0100 Subject: [PATCH 7/9] Sort type members in tree view. --- ILSpy/TreeNodes/TypeTreeNode.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs index 9effcead4..c7b39a7c0 100644 --- a/ILSpy/TreeNodes/TypeTreeNode.cs +++ b/ILSpy/TreeNodes/TypeTreeNode.cs @@ -96,10 +96,10 @@ namespace ICSharpCode.ILSpy.TreeNodes this.Children.Add(new BaseTypesTreeNode(type)); if (!type.IsSealed) this.Children.Add(new DerivedTypesTreeNode(parentAssemblyNode.AssemblyList, type)); - foreach (TypeDefinition nestedType in type.NestedTypes) { + foreach (TypeDefinition nestedType in type.NestedTypes.OrderBy(m => m.Name)) { this.Children.Add(new TypeTreeNode(nestedType, parentAssemblyNode)); } - foreach (FieldDefinition field in type.Fields) { + foreach (FieldDefinition field in type.Fields.OrderBy(m => m.Name)) { this.Children.Add(new FieldTreeNode(field)); } @@ -111,14 +111,14 @@ namespace ICSharpCode.ILSpy.TreeNodes defaultMemberName = defaultMemberAttribute.ConstructorArguments[0].Value as string; } - foreach (PropertyDefinition property in type.Properties) { + foreach (PropertyDefinition property in type.Properties.OrderBy(m => m.Name)) { this.Children.Add(new PropertyTreeNode(property, property.Name == defaultMemberName)); } - foreach (EventDefinition ev in type.Events) { + foreach (EventDefinition ev in type.Events.OrderBy(m => m.Name)) { this.Children.Add(new EventTreeNode(ev)); } HashSet accessorMethods = type.GetAccessorMethods(); - foreach (MethodDefinition method in type.Methods) { + foreach (MethodDefinition method in type.Methods.OrderBy(m => m.Name)) { if (!accessorMethods.Contains(method)) { this.Children.Add(new MethodTreeNode(method)); } From 2d18f5e3094b3539bc0700347c06aff68e29d7a5 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 16 Feb 2011 19:03:22 +0100 Subject: [PATCH 8/9] Members of a type are collapsed by default. --- ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs index c853ebdd1..f489d57eb 100644 --- a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs +++ b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs @@ -14,6 +14,7 @@ namespace Decompiler { readonly ITextOutput output; readonly Stack nodeStack = new Stack(); + int braceLevelWithinType = -1; public TextOutputFormatter(ITextOutput output) { @@ -64,8 +65,11 @@ namespace Decompiler public void OpenBrace(BraceStyle style) { - if (nodeStack.OfType().Count() <= 1) - output.MarkFoldStart(); + if (braceLevelWithinType >= 0 || nodeStack.Peek() is TypeDeclaration) + braceLevelWithinType++; + if (nodeStack.OfType().Count() <= 1) { + output.MarkFoldStart(defaultCollapsed: braceLevelWithinType == 1); + } output.WriteLine(); output.WriteLine("{"); output.Indent(); @@ -77,6 +81,8 @@ namespace Decompiler output.Write('}'); if (nodeStack.OfType().Count() <= 1) output.MarkFoldEnd(); + if (braceLevelWithinType >= 0) + braceLevelWithinType--; } public void Indent() From ed11a717a0c25b6a2b4a14946ebc01f34829d8e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Wed, 16 Feb 2011 20:58:08 +0000 Subject: [PATCH 9/9] Fixed bug in creation of try-catch ILAst blocks --- ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs index 9b6ffed6f..bb0c9cf03 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs @@ -106,7 +106,7 @@ namespace Decompiler List body = StackAnalysis(methodDef); - List ast = ConvertToAst(body, methodDef.Body.ExceptionHandlers); + List ast = ConvertToAst(body, new HashSet(methodDef.Body.ExceptionHandlers)); return ast; } @@ -292,7 +292,7 @@ namespace Decompiler return body; } - List ConvertToAst(List body, IEnumerable ehs) + List ConvertToAst(List body, HashSet ehs) { List ast = new List(); @@ -313,7 +313,8 @@ namespace Decompiler // Cut the try block { - List nestedEHs = ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd)).ToList(); + HashSet nestedEHs = new HashSet(ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd))); + ehs.ExceptWith(nestedEHs); int tryEndIdx; for (tryEndIdx = 0; tryEndIdx < body.Count && body[tryEndIdx].Offset != tryEnd; tryEndIdx++); tryCatchBlock.TryBlock = new ILBlock(ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs)); @@ -328,7 +329,8 @@ namespace Decompiler // Note that the end(exclusiove) instruction may not necessarly be in our body for (endInclusiveIndex = 0; body[endInclusiveIndex].Next.Offset != eh.HandlerEnd.Offset; endInclusiveIndex++); int count = 1 + endInclusiveIndex - startIndex; - List nestedEHs = 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)).ToList(); + 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); List handlerAst = ConvertToAst(body.CutRange(startIndex, count), nestedEHs); if (eh.HandlerType == ExceptionHandlerType.Catch) { tryCatchBlock.CatchBlocks.Add(new ILTryCatchBlock.CatchBlock() { @@ -342,7 +344,7 @@ namespace Decompiler } } - ehs = ehs.Where(eh => eh.TryStart.Offset > tryEnd).ToList(); + ehs.ExceptWith(handlers); ast.Add(tryCatchBlock); }