Пример #1
0
        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}");
        }
Пример #2
0
        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());
 }
Пример #4
0
        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}");
        }
Пример #5
0
        public Expression[] Extract(Expression expression)
        {
            Visit(expression);
            var result = externalExpressions.GroupBy(exp => ExpressionCompiler.DebugViewGetter(exp)).Select(grouping => grouping.First()).ToArray();

            externalExpressions.Clear();
            return(result);
        }
Пример #6
0
        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);
        }
Пример #7
0
        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)))));
        }
Пример #9
0
 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)));
 }