public static void AssertEqualsExpression <T>(this Expression <T> actual, Expression <T> expected) { var expectedDebugView = ExpressionCompiler.DebugViewGetter(expected.Simplify()); var actualDebugView = ExpressionCompiler.DebugViewGetter(actual.Simplify()); Assert.AreEqual(expectedDebugView, actualDebugView, $"Expected:\n{expectedDebugView}\nActual:\n{actualDebugView}"); }
protected override Expression VisitMethodCall(MethodCallExpression node) { var method = node.Method; if (method.IsGenericMethod) { method = method.GetGenericMethodDefinition(); } if (method == MutatorsHelperFunctions.CurrentIndexMethod) { var item = (MethodCallExpression)node.Arguments.Single(); if (!item.Method.IsEachMethod() && !item.Method.IsCurrentMethod()) { throw new InvalidOperationException(); } var collection = Visit(item.Arguments.Single()); var itemType = collection.Type.GetItemType(); return(Expression.Call(method.MakeGenericMethod(itemType), Expression.Call(item.Method.GetGenericMethodDefinition().MakeGenericMethod(itemType), collection))); } if (method.DeclaringType != typeof(Enumerable)) { return(base.VisitMethodCall(node)); } var obj = node.Arguments[0]; var arguments = node.Arguments.Skip(1).ToArray(); var visitedObj = Visit(obj); if (obj.Type == visitedObj.Type) { return(node.Update(node.Object, new[] { visitedObj }.Concat(arguments.Select(Visit)))); } var visitedArguments = new List <Expression>(); var path = Expression.Call(MutatorsHelperFunctions.CurrentMethod.MakeGenericMethod(obj.Type.GetItemType()), obj); foreach (var argument in arguments) { if (!(argument is LambdaExpression)) { visitedArguments.Add(Visit(argument)); } else { var lambdaArg = (LambdaExpression)argument; if (lambdaArg.Parameters.Count != 1) { throw new NotSupportedException("Unsupported lambda " + ExpressionCompiler.DebugViewGetter(lambdaArg)); } lambdaArg = Expression.Lambda(path, path.ExtractParameters()).Merge(lambdaArg); var visitedArg = Visit(lambdaArg.Body); var parameter = Expression.Parameter(visitedObj.Type.GetItemType()); var resolvedArg = new AliasesResolver(new List <KeyValuePair <Expression, Expression> > { new KeyValuePair <Expression, Expression>(parameter, Expression.Call(MutatorsHelperFunctions.CurrentMethod.MakeGenericMethod(visitedObj.Type.GetItemType()), visitedObj)) }).Visit(visitedArg); visitedArguments.Add(Expression.Lambda(resolvedArg, parameter)); } } return(Expression.Call(method.MakeGenericMethod(new[] { visitedObj.Type.GetItemType() }.Concat(node.Method.GetGenericArguments().Skip(1)).ToArray()), new[] { visitedObj }.Concat(visitedArguments))); }
protected override LambdaExpression[] GetDependencies() { return((Condition == null ? new LambdaExpression[0] : Condition.ExtractDependencies(Condition.Parameters.Where(parameter => parameter.Type == Type))) .Concat(Message == null ? new LambdaExpression[0] : Message.ExtractDependencies()) .GroupBy(lambda => ExpressionCompiler.DebugViewGetter(lambda)) .Select(grouping => grouping.First()) .ToArray()); }
public static void AssertEquivalentExpressions(this Expression actual, Expression expected) { var equivalent = ExpressionEquivalenceChecker.Equivalent(actual, expected, strictly: false, distinguishEachAndCurrent: true); var expectedDebugView = ExpressionCompiler.DebugViewGetter(expected.Simplify()); var actualDebugView = ExpressionCompiler.DebugViewGetter(actual.Simplify()); Assert.IsTrue(equivalent, $"Expressions are not equivalent.\nExpected:\n{expectedDebugView}\nActual:\n{actualDebugView}"); }
public Expression[] Extract(Expression expression) { Visit(expression); var result = externalExpressions.GroupBy(exp => ExpressionCompiler.DebugViewGetter(exp)).Select(grouping => grouping.First()).ToArray(); externalExpressions.Clear(); return(result); }
public Expression[] Extract(Expression expression) { nodesStack.Push(new NodeInfo(-1)); Visit(expression); var externalExpressions = new ExternalExpressionsTaker(externalNodes).Take(expression); var result = externalExpressions.GroupBy(exp => ExpressionCompiler.DebugViewGetter(exp)) .Select(grouping => grouping.First()).ToArray(); externalExpressions.Clear(); return(result); }
public LambdaExpression[] Extract(out LambdaExpression[] primaryDependencies, out LambdaExpression[] additionalDependencies) { var bodyWithoutCurrent = new MethodReplacer(MutatorsHelperFunctions.CurrentMethod, DependenciesExtractorHelper.ExternalCurrentMethod).Visit(lambda.Body); var bodyWithoutEach = new MethodReplacer(MutatorsHelperFunctions.EachMethod, DependenciesExtractorHelper.ExternalCurrentMethod).Visit(bodyWithoutCurrent); var body = Visit(bodyWithoutEach); var replacer = new MethodReplacer(DependenciesExtractorHelper.ExternalCurrentMethod, MutatorsHelperFunctions.CurrentMethod); if (body == null) { primaryDependencies = new LambdaExpression[0]; } else { var primaryDependenciez = new List <LambdaExpression>(); foreach (var dependency in ((NewArrayExpression)body).Expressions.Select(ClearConverts)) { if ((dependency is NewExpression)) { primaryDependenciez.Add(MakeLambda(dependency)); } else { var root = dependency.SmashToSmithereens()[0]; if (root.NodeType == ExpressionType.Parameter && parameters.Contains((ParameterExpression)root)) { primaryDependenciez.Add(MakeLambda(dependency)); } } } primaryDependencies = primaryDependenciez.Select(replacer.Visit).Cast <LambdaExpression>() .GroupBy(exp => ExpressionCompiler.DebugViewGetter(exp)).Select(grouping => grouping.First()).ToArray(); } additionalDependencies = dependencies.Select(dependency => Expression.Lambda(ClearConverts(dependency.Body), dependency.Parameters)).Where(dependency => { var root = dependency.Body.SmashToSmithereens()[0]; return(root.NodeType == ExpressionType.Parameter && parameters.Contains((ParameterExpression)root)); }).Select(replacer.Visit).Cast <LambdaExpression>().GroupBy(exp => ExpressionCompiler.DebugViewGetter(exp)).Select(grouping => grouping.First()).ToArray(); var result = new List <LambdaExpression>(additionalDependencies); foreach (var primaryDependency in primaryDependencies) { Extract(primaryDependency.Body, result); } return(result.GroupBy(exp => ExpressionCompiler.DebugViewGetter(exp)).Select(grouping => grouping.First()).ToArray()); }
private Expression VisitChain(Expression node) { var smithereens = node.SmashToSmithereens(); if (smithereens.Last().IsStringLengthPropertyAccess()) { smithereens = smithereens.Take(smithereens.Length - 1).ToArray(); } if (smithereens[0].NodeType == ExpressionType.Constant) { return(Expression.NewArrayInit(typeof(object))); } if (smithereens[0].NodeType != ExpressionType.Parameter) { return(base.Visit(node)); } var index = 0; while (index < smithereens.Length && smithereens[index].NodeType != ExpressionType.Call) { ++index; } var current = new CurrentDependencies { Prefix = smithereens[index - 1], AdditionalDependencies = new List <LambdaExpression>() }; while (index < smithereens.Length && current.Prefix != null) { var shard = smithereens[index]; var prevPrefix = current.Prefix; switch (shard.NodeType) { case ExpressionType.Call: { var methodCallExpression = (MethodCallExpression)shard; var method = methodCallExpression.Method; var arguments = (method.IsExtension() ? methodCallExpression.Arguments.Skip(1) : methodCallExpression.Arguments).ToArray(); if (method.IsGenericMethod) { method = method.GetGenericMethodDefinition(); } var methodProcessor = GetMethodProcessor(method); if (methodProcessor == null) { throw new NotSupportedException("Method '" + method + "' is not supported"); } methodProcessor(methodCallExpression.Method, current, arguments); break; } case ExpressionType.MemberAccess: { var member = ((MemberExpression)shard).Member; if (!(current.Prefix is NewExpression)) { current.Prefix = Expression.MakeMemberAccess(current.Prefix, member); } else { if (!current.Prefix.IsAnonymousTypeCreation() && !current.Prefix.IsTupleCreation()) { throw new NotSupportedException("An anonymous type or a tuple creation expected but was " + ExpressionCompiler.DebugViewGetter(current.Prefix)); } var newExpression = (NewExpression)current.Prefix; var type = newExpression.Type; MemberInfo[] members; if (member is PropertyInfo) { members = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); } else { throw new NotSupportedException(); } var i = Array.IndexOf(members, member); if (i < 0 || i >= newExpression.Arguments.Count) { throw new InvalidOperationException(); } var newArrayExpression = (NewArrayExpression)ClearConverts(newExpression.Arguments[i]); current.Prefix = newArrayExpression.Expressions.Count == 1 ? ClearConverts(newArrayExpression.Expressions[0]) : newArrayExpression; } } break; case ExpressionType.ArrayIndex: if (current.Prefix.Type.IsArray) { current.Prefix = Expression.MakeBinary(ExpressionType.ArrayIndex, current.Prefix, ((BinaryExpression)shard).Right); } break; case ExpressionType.Convert: if (current.Prefix.Type == typeof(object)) { current.Prefix = Expression.Convert(current.Prefix, shard.Type); } break; default: throw new InvalidOperationException("Node type '" + shard.NodeType + "' is not supported"); } if (current.Prefix == null) { current.Prefix = prevPrefix; break; } ++index; } var primaryDependencies = new List <Expression>(); if (current.Prefix != null) { if (current.Prefix is NewExpression) { if (!current.Prefix.IsAnonymousTypeCreation() && !current.Prefix.IsTupleCreation()) { primaryDependencies.AddRange(((NewExpression)current.Prefix).Arguments); } else { foreach (var expression in ((NewExpression)current.Prefix).Arguments.Select(ClearConverts)) { primaryDependencies.AddRange(((NewArrayExpression)expression).Expressions.Select(ClearConverts)); } } } else if (current.Prefix is NewArrayExpression) { primaryDependencies.AddRange(((NewArrayExpression)current.Prefix).Expressions.Select(ClearConverts)); } else if (IsPrimary(smithereens.Last())) { primaryDependencies.Add(current.Prefix); } } dependencies.AddRange(current.AdditionalDependencies); return(Expression.NewArrayInit(typeof(object), primaryDependencies.Select(dependency => Expression.Convert(dependency, typeof(object))))); }
public static void AssertEqualsExpression(this Expression actual, Expression expected) { Assert.AreEqual(ExpressionCompiler.DebugViewGetter(expected.Simplify()), ExpressionCompiler.DebugViewGetter(actual.Simplify())); }
private static string ExpressionToString(LambdaExpression lambda) { return(ExpressionCompiler.DebugViewGetter(Expression.Lambda(Expression.Convert(ClearConverts(lambda.Body), typeof(object)), lambda.Parameters))); }