Browse Source

Fix bugs in Expression.Quote/Expression.Invoke handling

Fix bugs in operator handling
pull/988/head
Siegfried Pammer 8 years ago
parent
commit
ad68204b04
  1. 58
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs
  2. 31
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

58
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ExpressionTrees.cs

@ -93,7 +93,7 @@ public class ExpressionTrees
public void ArrayIndex() public void ArrayIndex()
{ {
ExpressionTrees.ToCode(ExpressionTrees.X(), () => (new[] { ExpressionTrees.ToCode(ExpressionTrees.X(), () => (new int[3] {
3, 3,
4, 4,
5 5
@ -119,7 +119,7 @@ public class ExpressionTrees
public void ComplexGenericName() public void ComplexGenericName()
{ {
ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((Func<int, bool>)(x => x > 0))(0)); ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((Func<int, bool>)((int x) => x > 0))(0));
} }
public void DefaultValue() public void DefaultValue()
@ -134,7 +134,7 @@ public class ExpressionTrees
public void IndexerAccess() public void IndexerAccess()
{ {
var dict = Enumerable.Range(1, 20).ToDictionary(n => n.ToString()); Dictionary<string, int> dict = Enumerable.Range(1, 20).ToDictionary((int n) => n.ToString());
ExpressionTrees.ToCode(ExpressionTrees.X(), () => dict["3"] == 3); ExpressionTrees.ToCode(ExpressionTrees.X(), () => dict["3"] == 3);
} }
@ -213,28 +213,28 @@ public class ExpressionTrees
public void MembersDefault() public void MembersDefault()
{ {
ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(DateTime).Ticks == 0); ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(DateTime).Ticks == 0);
ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(int[]).Length == 0); ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((Array)null).Length == 0);
ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(Type).IsLayoutSequential); ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((Type)null).IsLayoutSequential);
ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(List<int>).Count); ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((List<int>)null).Count);
ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(int[]).Clone() == null); ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((Array)null).Clone() == null);
ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(Type).IsInstanceOfType(new object())); ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((Type)null).IsInstanceOfType(new object()));
ExpressionTrees.ToCode(ExpressionTrees.X(), () => default(List<int>).AsReadOnly()); ExpressionTrees.ToCode(ExpressionTrees.X(), () => ((List<int>)null).AsReadOnly());
} }
public void DoAssert() public void DoAssert()
{ {
field = 37; this.field = 37;
ExpressionTrees.ToCode(ExpressionTrees.X(), () => field != C()); ExpressionTrees.ToCode(ExpressionTrees.X(), () => this.field != this.C());
ExpressionTrees.ToCode(ExpressionTrees.X(), () => !ReferenceEquals(this, new ExpressionTrees())); ExpressionTrees.ToCode(ExpressionTrees.X(), () => !object.ReferenceEquals(this, new ExpressionTrees()));
ExpressionTrees.ToCode(ExpressionTrees.X(), () => MyEquals(this) && !MyEquals(default(ExpressionTrees))); ExpressionTrees.ToCode(ExpressionTrees.X(), () => this.MyEquals(this) && !this.MyEquals(null));
} }
int C() private int C()
{ {
return field + 5; return field + 5;
} }
bool MyEquals(ExpressionTrees other) private bool MyEquals(ExpressionTrees other)
{ {
return other != null && field == other.field; return other != null && field == other.field;
} }
@ -296,17 +296,17 @@ public class ExpressionTrees
ExpressionTrees.ToCode<int, Func<int, Func<int, int>>>(ExpressionTrees.X(), a => b => c => a + b + c); ExpressionTrees.ToCode<int, Func<int, Func<int, int>>>(ExpressionTrees.X(), a => b => c => a + b + c);
} }
bool Fizz(Func<int, bool> a) private bool Fizz(Func<int, bool> a)
{ {
return a(42); return a(42);
} }
bool Buzz(Func<int, bool> a) private bool Buzz(Func<int, bool> a)
{ {
return a(42); return a(42);
} }
bool Fizz(Func<string, bool> a) private bool Fizz(Func<string, bool> a)
{ {
return a("42"); return a("42");
} }
@ -322,7 +322,15 @@ public class ExpressionTrees
public void NewArrayAndExtensionMethod() 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() public void NewMultiDimArray()
@ -351,7 +359,10 @@ public class ExpressionTrees
CloseInput = false, CloseInput = false,
CheckCharacters = 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() public void Quoted()
@ -366,7 +377,12 @@ public class ExpressionTrees
public void QuotedWithAnonymous() 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() public void StaticCall()

31
ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

@ -19,6 +19,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
@ -134,7 +135,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Converts a Expression.Lambda call into an ILFunction. /// Converts a Expression.Lambda call into an ILFunction.
/// If the conversion fails, null is returned. /// If the conversion fails, null is returned.
/// </summary> /// </summary>
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) 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; return null;
@ -142,9 +143,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var parameterVariablesList = new List<ILVariable>(); var parameterVariablesList = new List<ILVariable>();
if (!ReadParameters(instruction.Arguments[1], parameterList, parameterVariablesList, new SimpleTypeResolveContext(context.Function.Method))) if (!ReadParameters(instruction.Arguments[1], parameterList, parameterVariablesList, new SimpleTypeResolveContext(context.Function.Method)))
return null; return null;
bool isQuotedLambda = instruction.Parent is CallInstruction call && call.Method.FullName == "System.Linq.Expressions.Expression.Quote";
var container = new BlockContainer(); var container = new BlockContainer();
var function = new ILFunction(instruction.Method.ReturnType.TypeArguments[0].TypeArguments.LastOrDefault() ?? context.TypeSystem.Compilation.FindType(KnownTypeCode.Void), parameterList, container); var functionType = instruction.Method.ReturnType.TypeArguments[0];
function.ExpressionTreeType = instruction.Method.ReturnType; 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); function.Variables.AddRange(parameterVariablesList);
lambdaStack.Push(function); lambdaStack.Push(function);
var bodyInstruction = ConvertInstruction(instruction.Arguments[0]); var bodyInstruction = ConvertInstruction(instruction.Arguments[0]);
@ -153,6 +157,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return null; return null;
container.ExpectedResultType = bodyInstruction.ResultType; container.ExpectedResultType = bodyInstruction.ResultType;
container.Blocks.Add(new Block() { Instructions = { new Leave(container, bodyInstruction) } }); 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; return function;
} }
@ -348,10 +356,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
Arguments = { left, right } Arguments = { left, right }
}; };
case 4: case 4:
//if (!trueOrFalse.IsMatch(invocation.Arguments[2])) if (!invocation.Arguments[2].MatchLdcI4(out var isLifted))
// return null; return null;
if (!MatchGetMethodFromHandle(invocation.Arguments[3], out method)) if (!MatchGetMethodFromHandle(invocation.Arguments[3], out method))
return null; return null;
if (isLifted != 0)
method = CSharpOperators.LiftUserDefinedOperator((IMethod)method);
return new Call((IMethod)method) { return new Call((IMethod)method) {
Arguments = { left, right } Arguments = { left, right }
}; };
@ -459,7 +469,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var right = ConvertInstruction(invocation.Arguments[1]); var right = ConvertInstruction(invocation.Arguments[1]);
if (right == null) if (right == null)
return 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 } }; return new Call((IMethod)method) { Arguments = { left, right } };
} }
// TODO: Sign?? // TODO: Sign??
@ -617,10 +630,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
Arguments = { left, right } Arguments = { left, right }
}; };
case 4: case 4:
//if (!trueOrFalse.IsMatch(invocation.Arguments[2])) if (!invocation.Arguments[2].MatchLdcI4(out var isLifted))
// return null; return null;
if (!MatchGetMethodFromHandle(invocation.Arguments[3], out method)) if (!MatchGetMethodFromHandle(invocation.Arguments[3], out method))
return null; return null;
if (isLifted != 0)
method = CSharpOperators.LiftUserDefinedOperator((IMethod)method);
return new Call((IMethod)method) { return new Call((IMethod)method) {
Arguments = { left, right } Arguments = { left, right }
}; };

Loading…
Cancel
Save