summaryrefslogtreecommitdiff
path: root/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs
diff options
context:
space:
mode:
Diffstat (limited to 'ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs')
-rw-r--r--ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs875
1 files changed, 875 insertions, 0 deletions
diff --git a/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs b/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs
new file mode 100644
index 00000000..2327200d
--- /dev/null
+++ b/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs
@@ -0,0 +1,875 @@
+// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using ICSharpCode.Decompiler.ILAst;
+using ICSharpCode.NRefactory.CSharp;
+using ICSharpCode.NRefactory.PatternMatching;
+using Mono.Cecil;
+
+namespace ICSharpCode.Decompiler.Ast.Transforms
+{
+ public class ExpressionTreeConverter
+ {
+ #region static TryConvert method
+ public static bool CouldBeExpressionTree(InvocationExpression expr)
+ {
+ if (expr != null && expr.Arguments.Count == 2) {
+ MethodReference mr = expr.Annotation<MethodReference>();
+ return mr != null && mr.Name == "Lambda" && mr.DeclaringType.FullName == "System.Linq.Expressions.Expression";
+ }
+ return false;
+ }
+
+ public static Expression TryConvert(DecompilerContext context, Expression expr)
+ {
+ Expression converted = new ExpressionTreeConverter(context).Convert(expr);
+ if (converted != null) {
+ converted.AddAnnotation(new ExpressionTreeLambdaAnnotation());
+ }
+ return converted;
+ }
+ #endregion
+
+ readonly DecompilerContext context;
+ Stack<LambdaExpression> activeLambdas = new Stack<LambdaExpression>();
+
+ ExpressionTreeConverter(DecompilerContext context)
+ {
+ this.context = context;
+ }
+
+ #region Main Convert method
+ Expression Convert(Expression expr)
+ {
+ InvocationExpression invocation = expr as InvocationExpression;
+ if (invocation != null) {
+ MethodReference mr = invocation.Annotation<MethodReference>();
+ if (mr != null && mr.DeclaringType.FullName == "System.Linq.Expressions.Expression") {
+ switch (mr.Name) {
+ case "Add":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.Add, false);
+ case "AddChecked":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.Add, true);
+ case "AddAssign":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Add, false);
+ case "AddAssignChecked":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Add, true);
+ case "And":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.BitwiseAnd);
+ case "AndAlso":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.ConditionalAnd);
+ case "AndAssign":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.BitwiseAnd);
+ case "ArrayAccess":
+ case "ArrayIndex":
+ return ConvertArrayIndex(invocation);
+ case "ArrayLength":
+ return ConvertArrayLength(invocation);
+ case "Assign":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Assign);
+ case "Call":
+ return ConvertCall(invocation);
+ case "Coalesce":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.NullCoalescing);
+ case "Condition":
+ return ConvertCondition(invocation);
+ case "Constant":
+ if (invocation.Arguments.Count >= 1)
+ return invocation.Arguments.First().Clone();
+ else
+ return NotSupported(expr);
+ case "Convert":
+ return ConvertCast(invocation, false);
+ case "ConvertChecked":
+ return ConvertCast(invocation, true);
+ case "Divide":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.Divide);
+ case "DivideAssign":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Divide);
+ case "Equal":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.Equality);
+ case "ExclusiveOr":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.ExclusiveOr);
+ case "ExclusiveOrAssign":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.ExclusiveOr);
+ case "Field":
+ return ConvertField(invocation);
+ case "GreaterThan":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.GreaterThan);
+ case "GreaterThanOrEqual":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.GreaterThanOrEqual);
+ case "Invoke":
+ return ConvertInvoke(invocation);
+ case "Lambda":
+ return ConvertLambda(invocation);
+ case "LeftShift":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.ShiftLeft);
+ case "LeftShiftAssign":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.ShiftLeft);
+ case "LessThan":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.LessThan);
+ case "LessThanOrEqual":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.LessThanOrEqual);
+ case "ListInit":
+ return ConvertListInit(invocation);
+ case "MemberInit":
+ return ConvertMemberInit(invocation);
+ case "Modulo":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.Modulus);
+ case "ModuloAssign":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Modulus);
+ case "Multiply":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.Multiply, false);
+ case "MultiplyChecked":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.Multiply, true);
+ case "MultiplyAssign":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Multiply, false);
+ case "MultiplyAssignChecked":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Multiply, true);
+ case "Negate":
+ return ConvertUnaryOperator(invocation, UnaryOperatorType.Minus, false);
+ case "NegateChecked":
+ return ConvertUnaryOperator(invocation, UnaryOperatorType.Minus, true);
+ case "New":
+ return ConvertNewObject(invocation);
+ case "NewArrayBounds":
+ return ConvertNewArrayBounds(invocation);
+ case "NewArrayInit":
+ return ConvertNewArrayInit(invocation);
+ case "Not":
+ return ConvertUnaryOperator(invocation, UnaryOperatorType.Not);
+ case "NotEqual":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.InEquality);
+ case "OnesComplement":
+ return ConvertUnaryOperator(invocation, UnaryOperatorType.BitNot);
+ case "Or":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.BitwiseOr);
+ case "OrAssign":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.BitwiseOr);
+ case "OrElse":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.ConditionalOr);
+ case "Property":
+ return ConvertProperty(invocation);
+ case "Quote":
+ if (invocation.Arguments.Count == 1)
+ return Convert(invocation.Arguments.Single());
+ else
+ return NotSupported(invocation);
+ case "RightShift":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.ShiftRight);
+ case "RightShiftAssign":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.ShiftRight);
+ case "Subtract":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.Subtract, false);
+ case "SubtractChecked":
+ return ConvertBinaryOperator(invocation, BinaryOperatorType.Subtract, true);
+ case "SubtractAssign":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Subtract, false);
+ case "SubtractAssignChecked":
+ return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Subtract, true);
+ case "TypeAs":
+ return ConvertTypeAs(invocation);
+ case "TypeIs":
+ return ConvertTypeIs(invocation);
+ }
+ }
+ }
+ IdentifierExpression ident = expr as IdentifierExpression;
+ if (ident != null) {
+ ILVariable v = ident.Annotation<ILVariable>();
+ if (v != null) {
+ foreach (LambdaExpression lambda in activeLambdas) {
+ foreach (ParameterDeclaration p in lambda.Parameters) {
+ if (p.Annotation<ILVariable>() == v)
+ return new IdentifierExpression(p.Name).WithAnnotation(v);
+ }
+ }
+ }
+ }
+ return NotSupported(expr);
+ }
+
+ Expression NotSupported(Expression expr)
+ {
+ Debug.WriteLine("Expression Tree Conversion Failed: '" + expr + "' is not supported");
+ return null;
+ }
+ #endregion
+
+ #region Convert Lambda
+ static readonly Expression emptyArrayPattern = new ArrayCreateExpression {
+ Type = new AnyNode(),
+ Arguments = { new PrimitiveExpression(0) }
+ };
+
+ Expression ConvertLambda(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count != 2)
+ return NotSupported(invocation);
+ LambdaExpression lambda = new LambdaExpression();
+ Expression body = invocation.Arguments.First();
+ ArrayCreateExpression parameterArray = invocation.Arguments.Last() as ArrayCreateExpression;
+ if (parameterArray == null)
+ return NotSupported(invocation);
+
+ var annotation = body.Annotation<ParameterDeclarationAnnotation>();
+ if (annotation != null) {
+ lambda.Parameters.AddRange(annotation.Parameters);
+ } else {
+ // No parameter declaration annotation found.
+ if (!emptyArrayPattern.IsMatch(parameterArray))
+ return null;
+ }
+
+ activeLambdas.Push(lambda);
+ Expression convertedBody = Convert(body);
+ activeLambdas.Pop();
+ if (convertedBody == null)
+ return null;
+ lambda.Body = convertedBody;
+ return lambda;
+ }
+ #endregion
+
+ #region Convert Field
+ static readonly Expression getFieldFromHandlePattern =
+ new TypePattern(typeof(FieldInfo)).ToType().Invoke(
+ "GetFieldFromHandle",
+ new LdTokenPattern("field").ToExpression().Member("FieldHandle"),
+ new OptionalNode(new TypeOfExpression(new AnyNode("declaringType")).Member("TypeHandle"))
+ );
+
+ Expression ConvertField(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count != 2)
+ return NotSupported(invocation);
+
+ Expression fieldInfoExpr = invocation.Arguments.ElementAt(1);
+ Match m = getFieldFromHandlePattern.Match(fieldInfoExpr);
+ if (!m.Success)
+ return NotSupported(invocation);
+
+ FieldReference fr = m.Get<AstNode>("field").Single().Annotation<FieldReference>();
+ if (fr == null)
+ return null;
+
+ Expression target = invocation.Arguments.ElementAt(0);
+ Expression convertedTarget;
+ if (target is NullReferenceExpression) {
+ if (m.Has("declaringType"))
+ convertedTarget = new TypeReferenceExpression(m.Get<AstType>("declaringType").Single().Clone());
+ else
+ convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(fr.DeclaringType));
+ } else {
+ convertedTarget = Convert(target);
+ if (convertedTarget == null)
+ return null;
+ }
+
+ return convertedTarget.Member(fr.Name).WithAnnotation(fr);
+ }
+ #endregion
+
+ #region Convert Property
+ static readonly Expression getMethodFromHandlePattern =
+ new TypePattern(typeof(MethodBase)).ToType().Invoke(
+ "GetMethodFromHandle",
+ new LdTokenPattern("method").ToExpression().Member("MethodHandle"),
+ new OptionalNode(new TypeOfExpression(new AnyNode("declaringType")).Member("TypeHandle"))
+ ).CastTo(new TypePattern(typeof(MethodInfo)));
+
+ Expression ConvertProperty(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count != 2)
+ return NotSupported(invocation);
+
+ Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1));
+ if (!m.Success)
+ return NotSupported(invocation);
+
+ MethodReference mr = m.Get<AstNode>("method").Single().Annotation<MethodReference>();
+ if (mr == null)
+ return null;
+
+ Expression target = invocation.Arguments.ElementAt(0);
+ Expression convertedTarget;
+ if (target is NullReferenceExpression) {
+ if (m.Has("declaringType"))
+ convertedTarget = new TypeReferenceExpression(m.Get<AstType>("declaringType").Single().Clone());
+ else
+ convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(mr.DeclaringType));
+ } else {
+ convertedTarget = Convert(target);
+ if (convertedTarget == null)
+ return null;
+ }
+
+ return convertedTarget.Member(GetPropertyName(mr)).WithAnnotation(mr);
+ }
+
+ string GetPropertyName(MethodReference accessor)
+ {
+ string name = accessor.Name;
+ if (name.StartsWith("get_", StringComparison.Ordinal) || name.StartsWith("set_", StringComparison.Ordinal))
+ name = name.Substring(4);
+ return name;
+ }
+ #endregion
+
+ #region Convert Call
+ Expression ConvertCall(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count < 2)
+ return NotSupported(invocation);
+
+ Expression target;
+ int firstArgumentPosition;
+
+ Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(0));
+ if (m.Success) {
+ target = null;
+ firstArgumentPosition = 1;
+ } else {
+ m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1));
+ if (!m.Success)
+ return NotSupported(invocation);
+ target = invocation.Arguments.ElementAt(0);
+ firstArgumentPosition = 2;
+ }
+
+ MethodReference mr = m.Get<AstNode>("method").Single().Annotation<MethodReference>();
+ if (mr == null)
+ return null;
+
+ Expression convertedTarget;
+ if (target == null || target is NullReferenceExpression) {
+ // static method
+ if (m.Has("declaringType"))
+ convertedTarget = new TypeReferenceExpression(m.Get<AstType>("declaringType").Single().Clone());
+ else
+ convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(mr.DeclaringType));
+ } else {
+ convertedTarget = Convert(target);
+ if (convertedTarget == null)
+ return null;
+ }
+
+ MemberReferenceExpression mre = convertedTarget.Member(mr.Name);
+ GenericInstanceMethod gim = mr as GenericInstanceMethod;
+ if (gim != null) {
+ foreach (TypeReference tr in gim.GenericArguments) {
+ mre.TypeArguments.Add(AstBuilder.ConvertType(tr));
+ }
+ }
+ IList<Expression> arguments = null;
+ if (invocation.Arguments.Count == firstArgumentPosition + 1) {
+ Expression argumentArray = invocation.Arguments.ElementAt(firstArgumentPosition);
+ arguments = ConvertExpressionsArray(argumentArray);
+ }
+ if (arguments == null) {
+ arguments = new List<Expression>();
+ foreach (Expression argument in invocation.Arguments.Skip(firstArgumentPosition)) {
+ Expression convertedArgument = Convert(argument);
+ if (convertedArgument == null)
+ return null;
+ arguments.Add(convertedArgument);
+ }
+ }
+ MethodDefinition methodDef = mr.Resolve();
+ if (methodDef != null && methodDef.IsGetter) {
+ PropertyDefinition indexer = AstMethodBodyBuilder.GetIndexer(methodDef);
+ if (indexer != null)
+ return new IndexerExpression(mre.Target.Detach(), arguments).WithAnnotation(indexer);
+ }
+ return new InvocationExpression(mre, arguments).WithAnnotation(mr);
+ }
+
+ Expression ConvertInvoke(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count != 2)
+ return NotSupported(invocation);
+
+ Expression convertedTarget = Convert(invocation.Arguments.ElementAt(0));
+ IList<Expression> convertedArguments = ConvertExpressionsArray(invocation.Arguments.ElementAt(1));
+ if (convertedTarget != null && convertedArguments != null)
+ return new InvocationExpression(convertedTarget, convertedArguments);
+ else
+ return null;
+ }
+ #endregion
+
+ #region Convert Binary Operator
+ static readonly Pattern trueOrFalse = new Choice {
+ new PrimitiveExpression(true),
+ new PrimitiveExpression(false)
+ };
+
+ Expression ConvertBinaryOperator(InvocationExpression invocation, BinaryOperatorType op, bool? isChecked = null)
+ {
+ if (invocation.Arguments.Count < 2)
+ return NotSupported(invocation);
+
+ Expression left = Convert(invocation.Arguments.ElementAt(0));
+ if (left == null)
+ return null;
+ Expression right = Convert(invocation.Arguments.ElementAt(1));
+ if (right == null)
+ return null;
+
+ BinaryOperatorExpression boe = new BinaryOperatorExpression(left, op, right);
+ if (isChecked != null)
+ boe.AddAnnotation(isChecked.Value ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation);
+
+ switch (invocation.Arguments.Count) {
+ case 2:
+ return boe;
+ case 3:
+ Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(2));
+ if (m.Success)
+ return boe.WithAnnotation(m.Get<AstNode>("method").Single().Annotation<MethodReference>());
+ else
+ return null;
+ case 4:
+ if (!trueOrFalse.IsMatch(invocation.Arguments.ElementAt(2)))
+ return null;
+ m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(3));
+ if (m.Success)
+ return boe.WithAnnotation(m.Get<AstNode>("method").Single().Annotation<MethodReference>());
+ else
+ return null;
+ default:
+ return NotSupported(invocation);
+ }
+ }
+ #endregion
+
+ #region Convert Assignment Operator
+ Expression ConvertAssignmentOperator(InvocationExpression invocation, AssignmentOperatorType op, bool? isChecked = null)
+ {
+ return NotSupported(invocation);
+ }
+ #endregion
+
+ #region Convert Unary Operator
+ Expression ConvertUnaryOperator(InvocationExpression invocation, UnaryOperatorType op, bool? isChecked = null)
+ {
+ if (invocation.Arguments.Count < 1)
+ return NotSupported(invocation);
+
+ Expression expr = Convert(invocation.Arguments.ElementAt(0));
+ if (expr == null)
+ return null;
+
+ UnaryOperatorExpression uoe = new UnaryOperatorExpression(op, expr);
+ if (isChecked != null)
+ uoe.AddAnnotation(isChecked.Value ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation);
+
+ switch (invocation.Arguments.Count) {
+ case 1:
+ return uoe;
+ case 2:
+ Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1));
+ if (m.Success)
+ return uoe.WithAnnotation(m.Get<AstNode>("method").Single().Annotation<MethodReference>());
+ else
+ return null;
+ default:
+ return NotSupported(invocation);
+ }
+ }
+ #endregion
+
+ #region Convert Condition Operator
+ Expression ConvertCondition(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count != 3)
+ return NotSupported(invocation);
+
+ Expression condition = Convert(invocation.Arguments.ElementAt(0));
+ Expression trueExpr = Convert(invocation.Arguments.ElementAt(1));
+ Expression falseExpr = Convert(invocation.Arguments.ElementAt(2));
+ if (condition != null && trueExpr != null && falseExpr != null)
+ return new ConditionalExpression(condition, trueExpr, falseExpr);
+ else
+ return null;
+ }
+ #endregion
+
+ #region Convert New Object
+ static readonly Expression newObjectCtorPattern = new TypePattern(typeof(MethodBase)).ToType().Invoke
+ (
+ "GetMethodFromHandle",
+ new LdTokenPattern("ctor").ToExpression().Member("MethodHandle"),
+ new OptionalNode(new TypeOfExpression(new AnyNode("declaringType")).Member("TypeHandle"))
+ ).CastTo(new TypePattern(typeof(ConstructorInfo)));
+
+ Expression ConvertNewObject(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count < 1 || invocation.Arguments.Count > 3)
+ return NotSupported(invocation);
+
+ Match m = newObjectCtorPattern.Match(invocation.Arguments.First());
+ if (!m.Success)
+ return NotSupported(invocation);
+
+ MethodReference ctor = m.Get<AstNode>("ctor").Single().Annotation<MethodReference>();
+ if (ctor == null)
+ return null;
+
+ AstType declaringTypeNode;
+ TypeReference declaringType;
+ if (m.Has("declaringType")) {
+ declaringTypeNode = m.Get<AstType>("declaringType").Single().Clone();
+ declaringType = declaringTypeNode.Annotation<TypeReference>();
+ } else {
+ declaringTypeNode = AstBuilder.ConvertType(ctor.DeclaringType);
+ declaringType = ctor.DeclaringType;
+ }
+ if (declaringTypeNode == null)
+ return null;
+
+ ObjectCreateExpression oce = new ObjectCreateExpression(declaringTypeNode);
+ if (invocation.Arguments.Count >= 2) {
+ IList<Expression> arguments = ConvertExpressionsArray(invocation.Arguments.ElementAtOrDefault(1));
+ if (arguments == null)
+ return null;
+ oce.Arguments.AddRange(arguments);
+ }
+ if (invocation.Arguments.Count >= 3 && declaringType.IsAnonymousType()) {
+ MethodDefinition resolvedCtor = ctor.Resolve();
+ if (resolvedCtor == null || resolvedCtor.Parameters.Count != oce.Arguments.Count)
+ return null;
+ AnonymousTypeCreateExpression atce = new AnonymousTypeCreateExpression();
+ var arguments = oce.Arguments.ToArray();
+ if (AstMethodBodyBuilder.CanInferAnonymousTypePropertyNamesFromArguments(arguments, resolvedCtor.Parameters)) {
+ oce.Arguments.MoveTo(atce.Initializers);
+ } else {
+ for (int i = 0; i < resolvedCtor.Parameters.Count; i++) {
+ atce.Initializers.Add(
+ new NamedExpression {
+ Name = resolvedCtor.Parameters[i].Name,
+ Expression = arguments[i].Detach()
+ });
+ }
+ }
+ return atce;
+ }
+
+ return oce;
+ }
+ #endregion
+
+ #region Convert ListInit
+ static readonly Pattern elementInitArrayPattern = ArrayInitializationPattern(
+ typeof(System.Linq.Expressions.ElementInit),
+ new TypePattern(typeof(System.Linq.Expressions.Expression)).ToType().Invoke("ElementInit", new AnyNode("methodInfos"), new AnyNode("addArgumentsArrays"))
+ );
+
+ Expression ConvertListInit(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count != 2)
+ return NotSupported(invocation);
+ ObjectCreateExpression oce = Convert(invocation.Arguments.ElementAt(0)) as ObjectCreateExpression;
+ if (oce == null)
+ return null;
+ Expression elementsArray = invocation.Arguments.ElementAt(1);
+ ArrayInitializerExpression initializer = ConvertElementInit(elementsArray);
+ if (initializer != null) {
+ oce.Initializer = initializer;
+ return oce;
+ } else {
+ return null;
+ }
+ }
+
+ ArrayInitializerExpression ConvertElementInit(Expression elementsArray)
+ {
+ IList<Expression> elements = ConvertExpressionsArray(elementsArray);
+ if (elements != null) {
+ return new ArrayInitializerExpression(elements);
+ }
+ Match m = elementInitArrayPattern.Match(elementsArray);
+ if (!m.Success)
+ return null;
+ ArrayInitializerExpression result = new ArrayInitializerExpression();
+ foreach (var elementInit in m.Get<Expression>("addArgumentsArrays")) {
+ IList<Expression> arguments = ConvertExpressionsArray(elementInit);
+ if (arguments == null)
+ return null;
+ result.Elements.Add(new ArrayInitializerExpression(arguments));
+ }
+ return result;
+ }
+ #endregion
+
+ #region Convert MemberInit
+ Expression ConvertMemberInit(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count != 2)
+ return NotSupported(invocation);
+ ObjectCreateExpression oce = Convert(invocation.Arguments.ElementAt(0)) as ObjectCreateExpression;
+ if (oce == null)
+ return null;
+ Expression elementsArray = invocation.Arguments.ElementAt(1);
+ ArrayInitializerExpression bindings = ConvertMemberBindings(elementsArray);
+ if (bindings == null)
+ return null;
+ oce.Initializer = bindings;
+ return oce;
+ }
+
+ static readonly Pattern memberBindingArrayPattern = ArrayInitializationPattern(typeof(System.Linq.Expressions.MemberBinding), new AnyNode("binding"));
+ static readonly INode expressionTypeReference = new TypeReferenceExpression(new TypePattern(typeof(System.Linq.Expressions.Expression)));
+
+ ArrayInitializerExpression ConvertMemberBindings(Expression elementsArray)
+ {
+ Match m = memberBindingArrayPattern.Match(elementsArray);
+ if (!m.Success)
+ return null;
+ ArrayInitializerExpression result = new ArrayInitializerExpression();
+ foreach (var binding in m.Get<Expression>("binding")) {
+ InvocationExpression bindingInvocation = binding as InvocationExpression;
+ if (bindingInvocation == null || bindingInvocation.Arguments.Count != 2)
+ return null;
+ MemberReferenceExpression bindingMRE = bindingInvocation.Target as MemberReferenceExpression;
+ if (bindingMRE == null || !expressionTypeReference.IsMatch(bindingMRE.Target))
+ return null;
+
+ Expression bindingTarget = bindingInvocation.Arguments.ElementAt(0);
+ Expression bindingValue = bindingInvocation.Arguments.ElementAt(1);
+
+ string memberName;
+ Match m2 = getMethodFromHandlePattern.Match(bindingTarget);
+ if (m2.Success) {
+ MethodReference setter = m2.Get<AstNode>("method").Single().Annotation<MethodReference>();
+ if (setter == null)
+ return null;
+ memberName = GetPropertyName(setter);
+ } else {
+ return null;
+ }
+
+ Expression convertedValue;
+ switch (bindingMRE.MemberName) {
+ case "Bind":
+ convertedValue = Convert(bindingValue);
+ break;
+ case "MemberBind":
+ convertedValue = ConvertMemberBindings(bindingValue);
+ break;
+ case "ListBind":
+ convertedValue = ConvertElementInit(bindingValue);
+ break;
+ default:
+ return null;
+ }
+ if (convertedValue == null)
+ return null;
+ result.Elements.Add(new NamedExpression(memberName, convertedValue));
+ }
+ return result;
+ }
+ #endregion
+
+ #region Convert Cast
+ Expression ConvertCast(InvocationExpression invocation, bool isChecked)
+ {
+ if (invocation.Arguments.Count < 2)
+ return null;
+ Expression converted = Convert(invocation.Arguments.ElementAt(0));
+ AstType type = ConvertTypeReference(invocation.Arguments.ElementAt(1));
+ if (converted != null && type != null) {
+ CastExpression cast = converted.CastTo(type);
+ cast.AddAnnotation(isChecked ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation);
+ switch (invocation.Arguments.Count) {
+ case 2:
+ return cast;
+ case 3:
+ Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(2));
+ if (m.Success)
+ return cast.WithAnnotation(m.Get<AstNode>("method").Single().Annotation<MethodReference>());
+ else
+ return null;
+ }
+ }
+ return null;
+ }
+ #endregion
+
+ #region ConvertExpressionsArray
+ static Pattern ArrayInitializationPattern(Type arrayElementType, INode elementPattern)
+ {
+ return new Choice {
+ new ArrayCreateExpression {
+ Type = new TypePattern(arrayElementType),
+ Arguments = { new PrimitiveExpression(0) }
+ },
+ new ArrayCreateExpression {
+ Type = new TypePattern(arrayElementType),
+ AdditionalArraySpecifiers = { new ArraySpecifier() },
+ Initializer = new ArrayInitializerExpression {
+ Elements = { new Repeat(elementPattern) }
+ }
+ }
+ };
+ }
+
+ static readonly Pattern expressionArrayPattern = ArrayInitializationPattern(typeof(System.Linq.Expressions.Expression), new AnyNode("elements"));
+
+ IList<Expression> ConvertExpressionsArray(Expression arrayExpression)
+ {
+ Match m = expressionArrayPattern.Match(arrayExpression);
+ if (m.Success) {
+ List<Expression> result = new List<Expression>();
+ foreach (Expression expr in m.Get<Expression>("elements")) {
+ Expression converted = Convert(expr);
+ if (converted == null)
+ return null;
+ result.Add(converted);
+ }
+ return result;
+ }
+ return null;
+ }
+ #endregion
+
+ #region Convert TypeAs/TypeIs
+ static readonly TypeOfPattern typeOfPattern = new TypeOfPattern("type");
+
+ AstType ConvertTypeReference(Expression typeOfExpression)
+ {
+ Match m = typeOfPattern.Match(typeOfExpression);
+ if (m.Success)
+ return m.Get<AstType>("type").Single().Clone();
+ else
+ return null;
+ }
+
+ Expression ConvertTypeAs(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count != 2)
+ return null;
+ Expression converted = Convert(invocation.Arguments.ElementAt(0));
+ AstType type = ConvertTypeReference(invocation.Arguments.ElementAt(1));
+ if (converted != null && type != null)
+ return new AsExpression(converted, type);
+ return null;
+ }
+
+ Expression ConvertTypeIs(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count != 2)
+ return null;
+ Expression converted = Convert(invocation.Arguments.ElementAt(0));
+ AstType type = ConvertTypeReference(invocation.Arguments.ElementAt(1));
+ if (converted != null && type != null)
+ return new IsExpression { Expression = converted, Type = type };
+ return null;
+ }
+ #endregion
+
+ #region Convert Array
+ Expression ConvertArrayIndex(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count != 2)
+ return NotSupported(invocation);
+
+ Expression targetConverted = Convert(invocation.Arguments.First());
+ if (targetConverted == null)
+ return null;
+
+ Expression index = invocation.Arguments.ElementAt(1);
+ Expression indexConverted = Convert(index);
+ if (indexConverted != null) {
+ return new IndexerExpression(targetConverted, indexConverted);
+ }
+ IList<Expression> indexesConverted = ConvertExpressionsArray(index);
+ if (indexesConverted != null) {
+ return new IndexerExpression(targetConverted, indexesConverted);
+ }
+ return null;
+ }
+
+ Expression ConvertArrayLength(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count != 1)
+ return NotSupported(invocation);
+
+ Expression targetConverted = Convert(invocation.Arguments.Single());
+ if (targetConverted != null)
+ return targetConverted.Member("Length");
+ else
+ return null;
+ }
+
+ Expression ConvertNewArrayInit(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count != 2)
+ return NotSupported(invocation);
+
+ AstType elementType = ConvertTypeReference(invocation.Arguments.ElementAt(0));
+ IList<Expression> elements = ConvertExpressionsArray(invocation.Arguments.ElementAt(1));
+ if (elementType != null && elements != null) {
+ if (ContainsAnonymousType(elementType)) {
+ elementType = null;
+ }
+ return new ArrayCreateExpression {
+ Type = elementType,
+ AdditionalArraySpecifiers = { new ArraySpecifier() },
+ Initializer = new ArrayInitializerExpression(elements)
+ };
+ }
+ return null;
+ }
+
+ Expression ConvertNewArrayBounds(InvocationExpression invocation)
+ {
+ if (invocation.Arguments.Count != 2)
+ return NotSupported(invocation);
+
+ AstType elementType = ConvertTypeReference(invocation.Arguments.ElementAt(0));
+ IList<Expression> arguments = ConvertExpressionsArray(invocation.Arguments.ElementAt(1));
+ if (elementType != null && arguments != null) {
+ if (ContainsAnonymousType(elementType)) {
+ elementType = null;
+ }
+ ArrayCreateExpression ace = new ArrayCreateExpression();
+ ace.Type = elementType;
+ ace.Arguments.AddRange(arguments);
+ return ace;
+ }
+ return null;
+ }
+
+ bool ContainsAnonymousType(AstType type)
+ {
+ foreach (AstType t in type.DescendantsAndSelf.OfType<AstType>()) {
+ TypeReference tr = t.Annotation<TypeReference>();
+ if (tr != null && tr.IsAnonymousType())
+ return true;
+ }
+ return false;
+ }
+ #endregion
+ }
+}