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)); }