Exemplo n.º 1
0
        internal override Expression VisitMethodCall(MethodCallExpression m)
        {
            m = (MethodCallExpression)base.VisitMethodCall(m);

            if (m.Method.IsStatic)
            {
                // handle operator overloads
                if (m.Method.Name.StartsWith("op_", StringComparison.Ordinal))
                {
                    // handle binary operator overloads
                    if (m.Arguments.Count == 2)
                    {
                        // CODE(C#): x == y
                        // ORIGINAL: MethodCallExpression(<op_Equality>, x, y)
                        // NORMALIZED: Equal(x, y)
                        switch (m.Method.Name)
                        {
                        case "op_Equality":
                            return(Expression.Equal(m.Arguments[0], m.Arguments[1], LiftToNull, m.Method));

                        case "op_Inequality":
                            return(Expression.NotEqual(m.Arguments[0], m.Arguments[1], LiftToNull, m.Method));

                        case "op_GreaterThan":
                            return(Expression.GreaterThan(m.Arguments[0], m.Arguments[1], LiftToNull, m.Method));

                        case "op_GreaterThanOrEqual":
                            return(Expression.GreaterThanOrEqual(m.Arguments[0], m.Arguments[1], LiftToNull, m.Method));

                        case "op_LessThan":
                            return(Expression.LessThan(m.Arguments[0], m.Arguments[1], LiftToNull, m.Method));

                        case "op_LessThanOrEqual":
                            return(Expression.LessThanOrEqual(m.Arguments[0], m.Arguments[1], LiftToNull, m.Method));

                        case "op_Multiply":
                            return(Expression.Multiply(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_Subtraction":
                            return(Expression.Subtract(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_Addition":
                            return(Expression.Add(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_Division":
                            return(Expression.Divide(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_Modulus":
                            return(Expression.Modulo(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_BitwiseAnd":
                            return(Expression.And(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_BitwiseOr":
                            return(Expression.Or(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_ExclusiveOr":
                            return(Expression.ExclusiveOr(m.Arguments[0], m.Arguments[1], m.Method));

                        default:
                            break;
                        }
                    }

                    // handle unary operator overloads
                    if (m.Arguments.Count == 1)
                    {
                        // CODE(C#): +x
                        // ORIGINAL: MethodCallExpression(<op_UnaryPlus>, x)
                        // NORMALIZED: UnaryPlus(x)
                        switch (m.Method.Name)
                        {
                        case "op_UnaryNegation":
                            return(Expression.Negate(m.Arguments[0], m.Method));

                        case "op_UnaryPlus":
                            return(Expression.UnaryPlus(m.Arguments[0], m.Method));

                        case "op_Explicit":
                        case "op_Implicit":
                            return(Expression.Convert(m.Arguments[0], m.Type, m.Method));

                        case "op_OnesComplement":
                        case "op_False":
                            return(Expression.Not(m.Arguments[0], m.Method));

                        default:
                            break;
                        }
                    }
                }

                // check for static Equals method
                if (m.Method.Name == "Equals" &&
                    m.Arguments.Count > 1)
                {
                    // CODE(C#): Object.Equals(x, y)
                    // ORIGINAL: MethodCallExpression(<object.Equals>, x, y)
                    // NORMALIZED: Equal(x, y)
                    return(Expression.Equal(m.Arguments[0], m.Arguments[1], false, m.Method));
                }

                // check for Microsoft.VisualBasic.CompilerServices.Operators.CompareString method
                if (m.Method.Name == "CompareString" &&
                    m.Method.DeclaringType.FullName == "Microsoft.VisualBasic.CompilerServices.Operators")
                {
                    // CODE(VB): x = y; where x and y are strings, a part of the expression looks like:
                    // ORIGINAL: MethodCallExpression(Microsoft.VisualBasic.CompilerServices.Operators.CompareString(x, y, False)
                    // NORMALIZED: see CreateCompareExpression method
                    return(CreateCompareExpression(m.Arguments[0], m.Arguments[1]));
                }

                // check for static Compare method
                if (m.Method.Name == "Compare" &&
                    m.Arguments.Count > 1 &&
                    m.Method.ReturnType == typeof(int))
                {
                    // CODE(C#): Class.Compare(x, y)
                    // ORIGINAL: MethodCallExpression(<Compare>, x, y)
                    // NORMALIZED: see CreateCompareExpression method
                    return(CreateCompareExpression(m.Arguments[0], m.Arguments[1]));
                }
            }
            else
            {
                // check for instance Equals method
                if (m.Method.Name == "Equals" &&
                    m.Arguments.Count > 0)
                {
                    // type-specific Equals method on spatial types becomes a call to the 'STEquals' spatial canonical function, so should remain in the expression tree.
                    var parameterType = m.Method.GetParameters()[0].ParameterType;
                    if (parameterType != typeof(DbGeography) &&
                        parameterType != typeof(DbGeometry))
                    {
                        // CODE(C#): x.Equals(y)
                        // ORIGINAL: MethodCallExpression(x, <Equals>, y)
                        // NORMALIZED: Equal(x, y)
                        return(CreateRelationalOperator(ExpressionType.Equal, m.Object, m.Arguments[0]));
                    }
                }

                // check for instance CompareTo method
                if (m.Method.Name == "CompareTo" &&
                    m.Arguments.Count == 1 &&
                    m.Method.ReturnType == typeof(int))
                {
                    // CODE(C#): x.CompareTo(y)
                    // ORIGINAL: MethodCallExpression(x.CompareTo(y))
                    // NORMALIZED: see CreateCompareExpression method
                    return(CreateCompareExpression(m.Object, m.Arguments[0]));
                }

                // check for List<> instance Contains method
                if (m.Method.Name == "Contains" &&
                    m.Arguments.Count == 1)
                {
                    var declaringType = m.Method.DeclaringType;
                    if (declaringType.IsGenericType() &&
                        declaringType.GetGenericTypeDefinition() == typeof(List <>))
                    {
                        // CODE(C#): List<T> x.Contains(y)
                        // ORIGINAL: MethodCallExpression(x.Contains(y))
                        // NORMALIZED: IEnumerable<T>.Contains(x, y)

                        MethodInfo containsMethod;
                        if (ReflectionUtil.TryLookupMethod(SequenceMethod.Contains, out containsMethod))
                        {
                            var enumerableContainsMethod = containsMethod.MakeGenericMethod(declaringType.GetGenericArguments());
                            return(Expression.Call(enumerableContainsMethod, m.Object, m.Arguments[0]));
                        }
                    }
                }
            }

            // check for coalesce operators added by the VB compiler to predicate arguments
            return(NormalizePredicateArgument(m));
        }
        internal override Expression VisitMethodCall(MethodCallExpression m)
        {
            m = (MethodCallExpression)base.VisitMethodCall(m);
            if (m.Method.IsStatic)
            {
                if (m.Method.Name.StartsWith("op_", StringComparison.Ordinal))
                {
                    if (m.Arguments.Count == 2)
                    {
                        switch (m.Method.Name)
                        {
                        case "op_Equality":
                            return((Expression)Expression.Equal(m.Arguments[0], m.Arguments[1], false, m.Method));

                        case "op_Inequality":
                            return((Expression)Expression.NotEqual(m.Arguments[0], m.Arguments[1], false, m.Method));

                        case "op_GreaterThan":
                            return((Expression)Expression.GreaterThan(m.Arguments[0], m.Arguments[1], false, m.Method));

                        case "op_GreaterThanOrEqual":
                            return((Expression)Expression.GreaterThanOrEqual(m.Arguments[0], m.Arguments[1], false, m.Method));

                        case "op_LessThan":
                            return((Expression)Expression.LessThan(m.Arguments[0], m.Arguments[1], false, m.Method));

                        case "op_LessThanOrEqual":
                            return((Expression)Expression.LessThanOrEqual(m.Arguments[0], m.Arguments[1], false, m.Method));

                        case "op_Multiply":
                            return((Expression)Expression.Multiply(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_Subtraction":
                            return((Expression)Expression.Subtract(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_Addition":
                            return((Expression)Expression.Add(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_Division":
                            return((Expression)Expression.Divide(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_Modulus":
                            return((Expression)Expression.Modulo(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_BitwiseAnd":
                            return((Expression)Expression.And(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_BitwiseOr":
                            return((Expression)Expression.Or(m.Arguments[0], m.Arguments[1], m.Method));

                        case "op_ExclusiveOr":
                            return((Expression)Expression.ExclusiveOr(m.Arguments[0], m.Arguments[1], m.Method));
                        }
                    }
                    if (m.Arguments.Count == 1)
                    {
                        switch (m.Method.Name)
                        {
                        case "op_UnaryNegation":
                            return((Expression)Expression.Negate(m.Arguments[0], m.Method));

                        case "op_UnaryPlus":
                            return((Expression)Expression.UnaryPlus(m.Arguments[0], m.Method));

                        case "op_Explicit":
                        case "op_Implicit":
                            return((Expression)Expression.Convert(m.Arguments[0], m.Type, m.Method));

                        case "op_OnesComplement":
                        case "op_False":
                            return((Expression)Expression.Not(m.Arguments[0], m.Method));
                        }
                    }
                }
                if (m.Method.Name == "Equals" && m.Arguments.Count > 1)
                {
                    return((Expression)Expression.Equal(m.Arguments[0], m.Arguments[1], false, m.Method));
                }
                if (m.Method.Name == "CompareString" && m.Method.DeclaringType.FullName == "Microsoft.VisualBasic.CompilerServices.Operators" || m.Method.Name == "Compare" && m.Arguments.Count > 1 && m.Method.ReturnType == typeof(int))
                {
                    return(this.CreateCompareExpression(m.Arguments[0], m.Arguments[1]));
                }
            }
            else
            {
                if (m.Method.Name == "Equals" && m.Arguments.Count > 0)
                {
                    Type parameterType = m.Method.GetParameters()[0].ParameterType;
                    if (parameterType != typeof(DbGeography) && parameterType != typeof(DbGeometry))
                    {
                        return((Expression)LinqExpressionNormalizer.CreateRelationalOperator(ExpressionType.Equal, m.Object, m.Arguments[0]));
                    }
                }
                if (m.Method.Name == "CompareTo" && m.Arguments.Count == 1 && m.Method.ReturnType == typeof(int))
                {
                    return(this.CreateCompareExpression(m.Object, m.Arguments[0]));
                }
                if (m.Method.Name == "Contains" && m.Arguments.Count == 1)
                {
                    Type       declaringType = m.Method.DeclaringType;
                    MethodInfo method;
                    if (declaringType.IsGenericType() && declaringType.GetGenericTypeDefinition() == typeof(List <>) && ReflectionUtil.TryLookupMethod(SequenceMethod.Contains, out method))
                    {
                        return((Expression)Expression.Call(method.MakeGenericMethod(declaringType.GetGenericArguments()), m.Object, m.Arguments[0]));
                    }
                }
            }
            return((Expression)LinqExpressionNormalizer.NormalizePredicateArgument(m));
        }