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