From df94edc2d4a5fc7d74ca8c4225d5c0983c06d170 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 2 Jun 2011 03:11:12 +0200 Subject: [PATCH 1/6] Fix InvalidCastException when hovering over a type reference. --- ILSpy/XmlDoc/XmlDocKeyProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ILSpy/XmlDoc/XmlDocKeyProvider.cs b/ILSpy/XmlDoc/XmlDocKeyProvider.cs index fc503c115..d4f1e646c 100644 --- a/ILSpy/XmlDoc/XmlDocKeyProvider.cs +++ b/ILSpy/XmlDoc/XmlDocKeyProvider.cs @@ -36,7 +36,7 @@ namespace ICSharpCode.ILSpy.XmlDoc StringBuilder b = new StringBuilder(); if (member is TypeReference) { b.Append("T:"); - AppendTypeName(b, (TypeDefinition)member); + AppendTypeName(b, (TypeReference)member); } else { if (member is FieldReference) b.Append("F:"); From 64f409ad28495bef3f36802b1a064fd284ace6dd Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 2 Jun 2011 18:06:51 +0200 Subject: [PATCH 2/6] Remove duplicate references in BamlDecompiler.Tests. --- ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj b/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj index 975dfc6ee..61cfa995c 100644 --- a/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj +++ b/ILSpy.BamlDecompiler/Tests/ILSpy.BamlDecompiler.Tests.csproj @@ -44,11 +44,9 @@ ..\..\ICSharpCode.Decompiler\Tests\nunit.framework.dll - 3.0 - 3.0 @@ -63,7 +61,6 @@ 3.5 - 3.0 From c31f9232c5efb0d8c90cfea244ed0976e7bee65d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Thu, 2 Jun 2011 17:01:07 +0100 Subject: [PATCH 3/6] Do not fall though the end of try-block. It should never happen in valid IL, but some obfuscators generate such code. Closes #164 --- ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs index f6edfad85..e569c83e8 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs @@ -281,6 +281,8 @@ namespace ICSharpCode.Decompiler.ILAst int varCount = methodDef.Body.Variables.Count; + var exceptionHandlerStarts = new HashSet(methodDef.Body.ExceptionHandlers.Select(eh => instrToByteCode[eh.HandlerStart])); + // Add known states if(methodDef.Body.HasExceptionHandlers) { foreach(ExceptionHandler ex in methodDef.Body.ExceptionHandlers) { @@ -347,7 +349,12 @@ namespace ICSharpCode.Decompiler.ILAst // Find all successors List branchTargets = new List(); if (!byteCode.Code.IsUnconditionalControlFlow()) { - branchTargets.Add(byteCode.Next); + if (exceptionHandlerStarts.Contains(byteCode.Next)) { + // Do not fall though down to exception handler + // It is invalid IL as per ECMA-335 §12.4.2.8.1, but some obfuscators produce it + } else { + branchTargets.Add(byteCode.Next); + } } if (byteCode.Operand is Instruction[]) { foreach(Instruction inst in (Instruction[])byteCode.Operand) { From 6fd28e8b6eb9f0c594024ef19a03fe4edacc0457 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Thu, 2 Jun 2011 17:50:48 +0100 Subject: [PATCH 4/6] Remove unreachable return statements. Closes #174. Closes #192 --- ICSharpCode.Decompiler/ILAst/GotoRemoval.cs | 19 ++++++++++++++++++- .../ILAst/ILAstOptimizer.cs | 4 ++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs b/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs index 351c28428..fafe13e1a 100644 --- a/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs +++ b/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs @@ -98,10 +98,27 @@ namespace ICSharpCode.Decompiler.ILAst } } - // Remove redundant return + // Remove redundant return at the end of method if (method.Body.Count > 0 && method.Body.Last().Match(ILCode.Ret) && ((ILExpression)method.Body.Last()).Arguments.Count == 0) { method.Body.RemoveAt(method.Body.Count - 1); } + + // Remove unreachable return statements + bool modified = false; + foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { + for (int i = 0; i < block.Body.Count - 1;) { + if (block.Body[i].IsUnconditionalControlFlow() && block.Body[i+1].Match(ILCode.Ret)) { + modified = true; + block.Body.RemoveAt(i+1); + } else { + i++; + } + } + } + if (modified) { + // More removals might be possible + new GotoRemoval().RemoveGotos(method); + } } IEnumerable GetParents(ILNode node) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index c4447f4d4..31bfc741f 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -56,6 +56,7 @@ namespace ICSharpCode.Decompiler.ILAst RemoveRedundantCode2, GotoRemoval, DuplicateReturns, + GotoRemoval2, ReduceIfNesting, InlineVariables3, CachedDelegateInitialization, @@ -182,6 +183,9 @@ namespace ICSharpCode.Decompiler.ILAst if (abortBeforeStep == ILAstOptimizationStep.DuplicateReturns) return; DuplicateReturnStatements(method); + if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval2) return; + new GotoRemoval().RemoveGotos(method); + if (abortBeforeStep == ILAstOptimizationStep.ReduceIfNesting) return; ReduceIfNesting(method); From 6daf7cb6bc102435d64acbae74b8534403ea1161 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 2 Jun 2011 19:30:17 +0200 Subject: [PATCH 5/6] Fix some compiler warnings. --- .../Tests/ICSharpCode.Decompiler.Tests.csproj | 2 +- .../TypeDeclaration.cs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 33227a313..13af1018c 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -13,8 +13,8 @@ False 4 false - 67,169 False + 67,169,1058,728 x86 diff --git a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs index 2efaab843..2acc523f4 100644 --- a/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs +++ b/ILSpy.BamlDecompiler/Ricciolo.StylesExplorer.MarkupReflection/TypeDeclaration.cs @@ -132,6 +132,11 @@ namespace Ricciolo.StylesExplorer.MarkupReflection else return false; } + + public override int GetHashCode() + { + return this.AssemblyId ^ this.Name.GetHashCode() ^ this.Namespace.GetHashCode(); + } } } From 9376ece056af882b0d081086d344b4a4518f8dee Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 2 Jun 2011 19:43:52 +0200 Subject: [PATCH 6/6] Fixed references to enum values nested within generic types. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 12 ++++++------ ICSharpCode.Decompiler/Tests/Generics.cs | 8 ++++++++ ICSharpCode.Decompiler/Tests/TestRunner.cs | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index f39a4cbf0..05e82499f 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -1501,13 +1501,13 @@ namespace ICSharpCode.Decompiler.Ast { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs) TypeDefinition enumDefinition = type.Resolve(); if (enumDefinition != null && enumDefinition.IsEnum) { + TypeCode enumBaseTypeCode = TypeCode.Int32; foreach (FieldDefinition field in enumDefinition.Fields) { if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val)) - return ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + return ConvertType(type).Member(field.Name).WithAnnotation(field); else if (!field.IsStatic && field.IsRuntimeSpecialName) - type = field.FieldType; // use primitive type of the enum + enumBaseTypeCode = TypeAnalysis.GetTypeCode(field.FieldType); // use primitive type of the enum } - TypeCode enumBaseTypeCode = TypeAnalysis.GetTypeCode(type); if (IsFlagsEnum(enumDefinition)) { long enumValue = val; Expression expr = null; @@ -1534,7 +1534,7 @@ namespace ICSharpCode.Decompiler.Ast continue; // skip None enum value if ((fieldValue & enumValue) == fieldValue) { - var fieldExpression = ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + var fieldExpression = ConvertType(type).Member(field.Name).WithAnnotation(field); if (expr == null) expr = fieldExpression; else @@ -1543,7 +1543,7 @@ namespace ICSharpCode.Decompiler.Ast enumValue &= ~fieldValue; } if ((fieldValue & negatedEnumValue) == fieldValue) { - var fieldExpression = ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + var fieldExpression = ConvertType(type).Member(field.Name).WithAnnotation(field); if (negatedExpr == null) negatedExpr = fieldExpression; else @@ -1561,7 +1561,7 @@ namespace ICSharpCode.Decompiler.Ast return new UnaryOperatorExpression(UnaryOperatorType.BitNot, negatedExpr); } } - return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(enumDefinition)); + return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(type)); } } TypeCode code = TypeAnalysis.GetTypeCode(type); diff --git a/ICSharpCode.Decompiler/Tests/Generics.cs b/ICSharpCode.Decompiler/Tests/Generics.cs index 9924583d6..9b7bd3fea 100644 --- a/ICSharpCode.Decompiler/Tests/Generics.cs +++ b/ICSharpCode.Decompiler/Tests/Generics.cs @@ -29,6 +29,12 @@ public static class Generics public Y Item2; } + public enum NestedEnum + { + A, + B + } + private T[] arr; public MyArray(int capacity) @@ -75,11 +81,13 @@ public static class Generics } } + private const Generics.MyArray.NestedEnum enumVal = Generics.MyArray.NestedEnum.A; private static Type type1 = typeof(List<>); private static Type type2 = typeof(Generics.MyArray<>); private static Type type3 = typeof(List<>.Enumerator); private static Type type4 = typeof(Generics.MyArray<>.NestedClass<>); private static Type type5 = typeof(List[]); + private static Type type6 = typeof(Generics.MyArray<>.NestedEnum); public static void MethodWithConstraint() where T : class, S where S : ICloneable, new() { diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index a05779ecc..52bef700c 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -158,7 +158,7 @@ namespace ICSharpCode.Decompiler.Tests { CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary { { "CompilerVersion", "v4.0" } }); CompilerParameters options = new CompilerParameters(); - options.CompilerOptions = "/unsafe"; + options.CompilerOptions = "/unsafe /o-"; options.ReferencedAssemblies.Add("System.Core.dll"); CompilerResults results = provider.CompileAssemblyFromSource(options, code); try {