From ad68204b04abfc7ada5da704092e6fe5a1257f7b Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 24 Nov 2017 02:09:17 +0100 Subject: [PATCH] Fix bugs in Expression.Quote/Expression.Invoke handling Fix bugs in operator handling --- .../TestCases/Pretty/ExpressionTrees.cs | 66 ++++++++++++------- .../IL/Transforms/TransformExpressionTrees.cs | 31 ++++++--- 2 files changed, 64 insertions(+), 33 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs index 96960e045..878670616 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs @@ -93,7 +93,7 @@ public class ExpressionTrees public void ArrayIndex() { - ExpressionTrees.ToCode(ExpressionTrees.X(), () => (new[] { + ExpressionTrees.ToCode(ExpressionTrees.X(), () => (new int[3] { 3, 4, 5 @@ -119,7 +119,7 @@ public class ExpressionTrees public void ComplexGenericName() { - ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((Func)(x => x > 0))(0)); + ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((Func)((int x) => x > 0))(0)); } public void DefaultValue() @@ -134,7 +134,7 @@ public class ExpressionTrees public void IndexerAccess() { - var dict = Enumerable.Range(1, 20).ToDictionary(n => n.ToString()); + Dictionary dict = Enumerable.Range(1, 20).ToDictionary((int n) => n.ToString()); ExpressionTrees.ToCode(ExpressionTrees.X(), () => dict["3"] == 3); } @@ -213,28 +213,28 @@ public class ExpressionTrees public void MembersDefault() { ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(DateTime).Ticks == 0); - ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(int[]).Length == 0); - ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(Type).IsLayoutSequential); - ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(List).Count); - ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(int[]).Clone() == null); - ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(Type).IsInstanceOfType(new object())); - ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(List).AsReadOnly()); + ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((Array)null).Length == 0); + ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((Type)null).IsLayoutSequential); + ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((List)null).Count); + ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((Array)null).Clone() == null); + ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((Type)null).IsInstanceOfType(new object())); + ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((List)null).AsReadOnly()); } public void DoAssert() { - field = 37; - ExpressionTrees.ToCode(ExpressionTrees.X(), () => field != C()); - ExpressionTrees.ToCode(ExpressionTrees.X(), () => !ReferenceEquals(this, new ExpressionTrees())); - ExpressionTrees.ToCode(ExpressionTrees.X(), () => MyEquals(this) && !MyEquals(default(ExpressionTrees))); + this.field = 37; + ExpressionTrees.ToCode(ExpressionTrees.X(), () => this.field != this.C()); + ExpressionTrees.ToCode(ExpressionTrees.X(), () => !object.ReferenceEquals(this, new ExpressionTrees())); + ExpressionTrees.ToCode(ExpressionTrees.X(), () => this.MyEquals(this) && !this.MyEquals(null)); } - int C() + private int C() { return field + 5; } - - bool MyEquals(ExpressionTrees other) + + private bool MyEquals(ExpressionTrees other) { return other != null && field == other.field; } @@ -295,18 +295,18 @@ public class ExpressionTrees { ExpressionTrees.ToCode>>(ExpressionTrees.X(), a => b => c => a + b + c); } - - bool Fizz(Func a) + + private bool Fizz(Func a) { return a(42); } - - bool Buzz(Func a) + + private bool Buzz(Func a) { return a(42); } - - bool Fizz(Func a) + + private bool Fizz(Func a) { return a("42"); } @@ -322,7 +322,15 @@ public class ExpressionTrees public void NewArrayAndExtensionMethod() { - ExpressionTrees.ToCode(ExpressionTrees.X(), () => new[] { 1.0, 2.01, 3.5 }.SequenceEqual(new[] { 1.0, 2.01, 3.5 })); + ExpressionTrees.ToCode(ExpressionTrees.X(), () => new double[3] { + 1.0, + 2.01, + 3.5 + }.SequenceEqual(new double[3] { + 1.0, + 2.01, + 3.5 + })); } public void NewMultiDimArray() @@ -351,7 +359,10 @@ public class ExpressionTrees CloseInput = false, CheckCharacters = false }; - ExpressionTrees.ToCode(ExpressionTrees.X(), () => new XmlReaderSettings { CloseInput = s.CloseInput, CheckCharacters = s.CheckCharacters }.Equals(s)); + ExpressionTrees.ToCode(ExpressionTrees.X(), () => new XmlReaderSettings { + CloseInput = s.CloseInput, + CheckCharacters = s.CheckCharacters + }.Equals(s)); } public void Quoted() @@ -366,7 +377,12 @@ public class ExpressionTrees public void QuotedWithAnonymous() { - ExpressionTrees.ToCode(ExpressionTrees.X(), () => new[] { new { X = "a", Y = "b" } }.Select(o => o.X + o.Y).Single()); + ExpressionTrees.ToCode(ExpressionTrees.X(), () => new[] { + new { + X = "a", + Y = "b" + } + }.Select(o => o.X + o.Y).Single()); } public void StaticCall() diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs index 3a3184a30..705abb17b 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.Linq; +using ICSharpCode.Decompiler.CSharp.Resolver; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.Util; @@ -134,7 +135,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// Converts a Expression.Lambda call into an ILFunction. /// If the conversion fails, null is returned. /// - ILFunction ConvertLambda(CallInstruction instruction) + ILInstruction ConvertLambda(CallInstruction instruction) { if (instruction.Method.Name != "Lambda" || instruction.Arguments.Count != 2 || instruction.Method.ReturnType.FullName != "System.Linq.Expressions.Expression" || instruction.Method.ReturnType.TypeArguments.Count != 1) return null; @@ -142,9 +143,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms var parameterVariablesList = new List(); if (!ReadParameters(instruction.Arguments[1], parameterList, parameterVariablesList, new SimpleTypeResolveContext(context.Function.Method))) return null; + bool isQuotedLambda = instruction.Parent is CallInstruction call && call.Method.FullName == "System.Linq.Expressions.Expression.Quote"; var container = new BlockContainer(); - var function = new ILFunction(instruction.Method.ReturnType.TypeArguments[0].TypeArguments.LastOrDefault() ?? context.TypeSystem.Compilation.FindType(KnownTypeCode.Void), parameterList, container); - function.ExpressionTreeType = instruction.Method.ReturnType; + var functionType = instruction.Method.ReturnType.TypeArguments[0]; + var function = new ILFunction(functionType.TypeArguments.LastOrDefault() ?? context.TypeSystem.Compilation.FindType(KnownTypeCode.Void), parameterList, container); + if (isQuotedLambda || lambdaStack.Count == 0) + function.ExpressionTreeType = instruction.Method.ReturnType; function.Variables.AddRange(parameterVariablesList); lambdaStack.Push(function); var bodyInstruction = ConvertInstruction(instruction.Arguments[0]); @@ -153,6 +157,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms return null; container.ExpectedResultType = bodyInstruction.ResultType; container.Blocks.Add(new Block() { Instructions = { new Leave(container, bodyInstruction) } }); + if (!isQuotedLambda && lambdaStack.Count > 0) + return new NewObj(functionType.GetConstructors().Single()) { + Arguments = { new LdNull(), function } + }; return function; } @@ -348,10 +356,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms Arguments = { left, right } }; case 4: - //if (!trueOrFalse.IsMatch(invocation.Arguments[2])) - // return null; + if (!invocation.Arguments[2].MatchLdcI4(out var isLifted)) + return null; if (!MatchGetMethodFromHandle(invocation.Arguments[3], out method)) return null; + if (isLifted != 0) + method = CSharpOperators.LiftUserDefinedOperator((IMethod)method); return new Call((IMethod)method) { Arguments = { left, right } }; @@ -459,7 +469,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms var right = ConvertInstruction(invocation.Arguments[1]); if (right == null) return null; - if (invocation.Arguments.Count == 3 && MatchGetMethodFromHandle(invocation.Arguments[2], out var method)) { + if (invocation.Arguments.Count == 4 && invocation.Arguments[2].MatchLdcI4(out var isLifted) && MatchGetMethodFromHandle(invocation.Arguments[3], out var method)) { + if (isLifted != 0) { + method = CSharpOperators.LiftUserDefinedOperator((IMethod)method); + } return new Call((IMethod)method) { Arguments = { left, right } }; } // TODO: Sign?? @@ -617,10 +630,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms Arguments = { left, right } }; case 4: - //if (!trueOrFalse.IsMatch(invocation.Arguments[2])) - // return null; + if (!invocation.Arguments[2].MatchLdcI4(out var isLifted)) + return null; if (!MatchGetMethodFromHandle(invocation.Arguments[3], out method)) return null; + if (isLifted != 0) + method = CSharpOperators.LiftUserDefinedOperator((IMethod)method); return new Call((IMethod)method) { Arguments = { left, right } };