// 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.CSharp.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(); 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 activeLambdas = new Stack(); private 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(); 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(); if (v != null) { foreach (LambdaExpression lambda in activeLambdas) { foreach (ParameterDeclaration p in lambda.Parameters) { if (p.Annotation() == 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(); 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("field").Single().Annotation(); 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("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("method").Single().Annotation(); 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("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("method").Single().Annotation(); if (mr == null) return null; Expression convertedTarget; if (target == null || target is NullReferenceExpression) { // static method if (m.Has("declaringType")) convertedTarget = new TypeReferenceExpression(m.Get("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 arguments = null; if (invocation.Arguments.Count == firstArgumentPosition + 1) { Expression argumentArray = invocation.Arguments.ElementAt(firstArgumentPosition); arguments = ConvertExpressionsArray(argumentArray); } if (arguments == null) { arguments = new List(); 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 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("method").Single().Annotation()); 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("method").Single().Annotation()); 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("method").Single().Annotation()); 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("ctor").Single().Annotation(); if (ctor == null) return null; AstType declaringTypeNode; TypeReference declaringType; if (m.Has("declaringType")) { declaringTypeNode = m.Get("declaringType").Single().Clone(); declaringType = declaringTypeNode.Annotation(); } 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 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 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("addArgumentsArrays")) { IList 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("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("method").Single().Annotation(); 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("method").Single().Annotation()); 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 ConvertExpressionsArray(Expression arrayExpression) { Match m = expressionArrayPattern.Match(arrayExpression); if (m.Success) { List result = new List(); foreach (Expression expr in m.Get("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("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 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 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 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()) { TypeReference tr = t.Annotation(); if (tr != null && tr.IsAnonymousType()) return true; } return false; } #endregion } }