/// <summary>Visits a method call.</summary> /// <param name="m">The method call to visit.</param> /// <returns>The visited expression.</returns> internal override Expression VisitMethodCall(MethodCallExpression m) { // Select - we should mark it with ResourceType of the return type of the Func var selectMatch = ExpressionUtil.MatchSelectCall(m); if (selectMatch != null) { Expression result = base.VisitMethodCall(m); selectMatch = ExpressionUtil.MatchSelectCall(result); if (selectMatch != null) { return(this.annotations.PropagateResourceType(selectMatch.LambdaBody, result)); } } // SelectMany - we should mark it with ResourceType of the return type of the Func var selectManyMatch = ExpressionUtil.MatchSelectManyCall(m); if (selectManyMatch != null) { Expression result = base.VisitMethodCall(m); selectManyMatch = ExpressionUtil.MatchSelectManyCall(result); if (selectManyMatch != null) { return(this.annotations.PropagateResourceType(selectManyMatch.LambdaBody, result)); } } // Where - simply propagate the resource type of the source as it doesn't change the results (just filters them) var whereMatch = ExpressionUtil.MatchWhereCall(m); if (whereMatch != null) { Expression result = base.VisitMethodCall(m); whereMatch = ExpressionUtil.MatchWhereCall(result); if (whereMatch != null) { return(this.annotations.PropagateResourceType(whereMatch.Source, result)); } } // OrderBy/ThenBy - simply propagate the resource type of the source as it doesn't change the results (just sorts them) var orderByMatch = ExpressionUtil.MatchOrderByCall(m) ?? ExpressionUtil.MatchThenByCall(m); if (orderByMatch != null) { Expression result = base.VisitMethodCall(m); orderByMatch = ExpressionUtil.MatchOrderByCall(result) ?? ExpressionUtil.MatchThenByCall(result); if (orderByMatch != null) { return(this.annotations.PropagateResourceType(orderByMatch.Source, result)); } } return(base.VisitMethodCall(m)); }
/// <summary> /// ConditionalExpression visit method /// </summary> /// <param name="c">The ConditionalExpression expression to visit</param> /// <returns> /// The visited ConditionalExpression expression /// </returns> internal override Expression VisitConditional(ConditionalExpression c) { var nullEqualConditionalMatch = ExpressionUtil.MatchNullEqualConditional(c); if (nullEqualConditionalMatch != null && nullEqualConditionalMatch.ComparisonOperand.Type == typeof(String)) { if (((MemberExpression)nullEqualConditionalMatch.ComparisonOperand).Member.Name == ((MemberExpression)((MethodCallExpression)((UnaryExpression)nullEqualConditionalMatch.IfNotNull).Operand).Object).Member.Name) { return(ExpressionUtil.RemoveConversionsAndTypeAs(nullEqualConditionalMatch.IfNotNull)); } } return(base.VisitConditional(c)); }
/// <summary> /// Optimizes the filter contains expressions. /// </summary> /// <param name="expr">The expr.</param> /// <returns></returns> private static Expression OptimizeFilterContainsExpressions(Expression expr) { var nullEqualConditionalMatch = ExpressionUtil.MatchNullEqualConditional(expr); if (nullEqualConditionalMatch != null && nullEqualConditionalMatch.ComparisonOperand.Type == typeof(String)) { if (((MemberExpression)nullEqualConditionalMatch.ComparisonOperand).Member.Name == ((MemberExpression)((MethodCallExpression)((UnaryExpression)nullEqualConditionalMatch.IfNotNull).Operand).Object).Member.Name) { return(ExpressionUtil.RemoveConversionsAndTypeAs(nullEqualConditionalMatch.IfNotNull)); } } return(expr); }
/// <summary> /// Visits the method call skip projections. /// </summary> /// <param name="m">The m.</param> /// <returns></returns> protected Expression VisitMethodCallSkipProjections(MethodCallExpression m) { var selectMatch = ExpressionUtil.MatchSelectCall(m); if (selectMatch != null) { Expression source = this.Visit(selectMatch.Source); return(this.Annotations.PropagateResourceType( selectMatch.Lambda, Expression.Call(selectMatch.MethodCall.Method, source, selectMatch.Lambda))); } else { return(base.VisitMethodCall(m)); } }
/// <summary> /// Visits the method call. /// </summary> /// <param name="m">The m.</param> /// <returns></returns> internal override Expression VisitMethodCall(MethodCallExpression m) { var whereMatch = ExpressionUtil.MatchWhereCall(m); if (whereMatch != null) { Expression source = this.Visit(whereMatch.Source); LambdaExpression lambda = Expression.Lambda( OptimizeFilterNullableBooleanToCondition(this.Visit(whereMatch.LambdaBody)), whereMatch.Lambda.Parameters.ToArray()); return(Expression.Call( whereMatch.MethodCall.Method, source, lambda)); } return(VisitMethodCallSkipProjections(m)); }
/// <summary>Determines if the <paramref name="expr"/> is a call to ThenBy.</summary> /// <param name="expr">Expression to inspect.</param> /// <returns>Instance of the <see cref="OrderByCallMatch"/> class if the <paramref name="expr"/> is a ThenBy call, /// or null otherwise.</returns> internal static OrderByCallMatch MatchThenByCall(Expression expr) { if (expr.NodeType == ExpressionType.Call && TypeSystem.IsMethodLinqThenBy(((MethodCallExpression)expr).Method)) { MethodCallExpression call = (MethodCallExpression)expr; LambdaExpression lambda = (LambdaExpression)ExpressionUtil.RemoveQuotes(call.Arguments[1]); Expression body = ExpressionUtil.RemoveQuotes(lambda.Body); return(new OrderByCallMatch { MethodCall = call, Source = call.Arguments[0], Lambda = lambda, LambdaBody = body }); } else { return(null); } }
/// <summary> /// Optimizes the filter nullable boolean to condition. /// </summary> /// <param name="expr">The expr.</param> /// <returns></returns> private static Expression OptimizeFilterNullableBooleanToCondition(Expression expr) { if (expr.Type == typeof(bool)) { var nullEqualConditionalMatch = ExpressionUtil.MatchNullEqualConditional(expr); if (nullEqualConditionalMatch != null && nullEqualConditionalMatch.ComparisonOperand.Type == typeof(bool?) && ExpressionUtil.IsFalseConstant(nullEqualConditionalMatch.IfNull) && ExpressionUtil.IsMemberAccess(nullEqualConditionalMatch.IfNotNull, "Value")) { // (c == null) ? false : c.Value (bool?)c // => // c == (bool?)true return(Expression.Equal( nullEqualConditionalMatch.ComparisonOperand, Expression.Constant(true, typeof(bool?)))); } } return(expr); }
/// <summary>Visits method call expression.</summary> /// <param name="m">The method call expression.</param> /// <returns>The visited expression.</returns> internal override Expression VisitMethodCall(MethodCallExpression m) { if (m.Method.Name == "Where") { Expression source = this.Visit(m.Arguments[0]); Expression lambdaArg = this.Visit(m.Arguments[1]); LambdaExpression lambda = (LambdaExpression)ExpressionUtil.RemoveQuotes(lambdaArg); Expression body = ExpressionUtil.RemoveQuotes(lambda.Body); Expression newBody; newBody = this.SimplifyBoolComparison(body); if (newBody != null) { return(Expression.Call( m.Method, source, Expression.Lambda(newBody, lambda.Parameters.ToArray()))); } } return(base.VisitMethodCall(m)); }
/// <summary>Visits a method call.</summary> /// <param name="m">The method call to visit.</param> /// <returns>The visited expression.</returns> internal override Expression VisitMethodCall(MethodCallExpression m) { if (m.Method == GetValueMethodInfo) { ResourceProperty property = (ResourceProperty)((ConstantExpression)m.Arguments[1]).Value; return(this.Annotations.AnnotateResourceProperty( Expression.Property(this.Visit(m.Arguments[0]), property.Name), property)); } if (m.Method.IsGenericMethod && m.Method.GetGenericMethodDefinition() == GetSequenceValueMethodInfo) { ResourceProperty property = (ResourceProperty)((ConstantExpression)m.Arguments[1]).Value; return(this.Annotations.AnnotateResourceProperty( Expression.Property(this.Visit(m.Arguments[0]), property.Name), property)); } if (m.Method == ConvertMethodInfo) { ResourceType type = (ResourceType)((ConstantExpression)m.Arguments[1]).Value; return(this.Annotations.AnnotateResourceType( Expression.Convert(this.Visit(m.Arguments[0]), type.InstanceType), type)); } if (m.Method == TypeIsMethodInfo) { ResourceType type = (ResourceType)((ConstantExpression)m.Arguments[1]).Value; return(Expression.TypeIs( this.Visit(m.Arguments[0]), type.InstanceType)); } var selectMatch = ExpressionUtil.MatchSelectCall(m); if (selectMatch != null) { // Annotate the source first Expression source = this.Visit(selectMatch.Source); // Annotate the lambda parameter with the source type this.Annotations.PropagateResourceType( source, selectMatch.Lambda.Parameters[0]); // Now annotate the lambda LambdaExpression lambda = (LambdaExpression)this.Visit(selectMatch.Lambda); Expression body = lambda.Body; return(this.Annotations.PropagateResourceType( body, Expression.Call(selectMatch.MethodCall.Method, source, lambda))); } var selectManyMatch = ExpressionUtil.MatchSelectManyCall(m); if (selectManyMatch != null) { // Annotate the lambda parameter with the source type this.Annotations.PropagateResourceType( selectManyMatch.Source, selectManyMatch.Lambda.Parameters[0]); return(base.VisitMethodCall(m)); } var whereMatch = ExpressionUtil.MatchWhereCall(m); if (whereMatch != null) { // Annotate the lambda parameter with the source type this.Annotations.PropagateResourceType( whereMatch.Source, whereMatch.Lambda.Parameters[0]); return(base.VisitMethodCall(m)); } var orderByMatch = ExpressionUtil.MatchOrderByCall(m) ?? ExpressionUtil.MatchThenByCall(m); if (orderByMatch != null) { // Annotate the lambda parameter with the source type this.Annotations.PropagateResourceType( orderByMatch.Source, orderByMatch.Lambda.Parameters[0]); return(base.VisitMethodCall(m)); } return(base.VisitMethodCall(m)); }