public static bool Test(Expression ex, params MemberInfo[] safeMembers)
        {
            var visitor = new IsConditionSafeVisitor();

            visitor.SafeMembers = safeMembers;
            visitor.Visit(ex);
            return(visitor.IsSafe);
        }
 /// <summary>
 /// Tries to combine nested filters;
 /// move 'MergeByName' nodes out of filter, if possible
 /// </summary>
 QueryNode ReorderFilter(Filter filter)
 {
     if (filter.Target is Filter)
     {
         // x.Filter(y).Filter(z) -> x.Filter(y && z)
         Filter innerFilter = (Filter)filter.Target;
         return(ReorderFilter(new Filter(innerFilter.Target, innerFilter.Conditions.Concat(filter.Conditions).ToArray())));
     }
     else if (filter.Target is MergeByName)
     {
         // x.MergeByName().Filter(<criteria>) -> x.Filter(x, <criteria>).MergeByName() for some safe criterias
         QueryNode innerTarget = filter.Target.Target;
         var       conditionsToMoveIntoFilter = filter.Conditions.Where(c => IsConditionSafeVisitor.Test(c, SafeMembersForMoveIntoMergeByName)).ToArray();
         if (conditionsToMoveIntoFilter.Length != 0)
         {
             MergeByName newTarget = new MergeByName(ReorderFilter(new Filter(innerTarget, conditionsToMoveIntoFilter)));
             var         conditionsKeptOutsideFilter = filter.Conditions.Except(conditionsToMoveIntoFilter).ToArray();
             if (conditionsKeptOutsideFilter.Length == 0)
             {
                 return(newTarget);
             }
             else
             {
                 return(new Filter(newTarget, conditionsKeptOutsideFilter));
             }
         }
         else
         {
             return(filter);
         }
     }
     else
     {
         return(filter);
     }
 }
		public static bool Test(Expression ex, params MemberInfo[] safeMembers)
		{
			var visitor = new IsConditionSafeVisitor();
			visitor.SafeMembers = safeMembers;
			visitor.Visit(ex);
			return visitor.IsSafe;
		}
        QueryNode VisitMergeByName(MergeByName merge)
        {
            // First optimize the Target expression
            QueryNode target = Visit(merge.Target);

            if (target is MergeByName)
            {
                // x.MergeByName().MergeByName() -> x.MergeByName()
                return(target);
            }
            if (target == AllCalls.Instance)
            {
                // AllCalls.MergeByName() -> AllFunctions
                return(new AllFunctions());
            }
            if (target is Filter && target.Target == AllCalls.Instance)
            {
                // AllCalls.Filter(criteria).MergeByName() -> AllFunctions.Filter(criteria)
                // If criteria accesses no CallTreeNode properties except for NameMapping.
                // Criteria of the form 'start <= c.DataSetID && c.DataSetID <= end' will be converted into AllFunctions(start,end)
                List <LambdaExpression> newConditions = new List <LambdaExpression>();
                bool allIsSafe      = true;
                int  startDataSetID = -1;
                int  endDataSetID   = -1;
                foreach (LambdaExpression condition in ((Filter)target).Conditions)
                {
                    if (IsConditionSafeVisitor.Test(condition, SafeMembersForMoveIntoMergeByName))
                    {
                        newConditions.Add(condition);
                    }
                    else if (condition.Body.NodeType == ExpressionType.AndAlso && startDataSetID < 0)
                    {
                        // try match 'constant <= c.DataSetID && c.DataSetID <= constant', but only if we
                        // haven't found it already (startDataSetID is still -1)
                        BinaryExpression bin = (BinaryExpression)condition.Body;
                        if (bin.Left.NodeType == ExpressionType.LessThanOrEqual && bin.Right.NodeType == ExpressionType.LessThanOrEqual)
                        {
                            BinaryExpression left  = (BinaryExpression)bin.Left;
                            BinaryExpression right = (BinaryExpression)bin.Right;
                            if (left.Left.NodeType == ExpressionType.Constant && left.Right.NodeType == ExpressionType.MemberAccess &&
                                right.Left.NodeType == ExpressionType.MemberAccess && right.Right.NodeType == ExpressionType.Constant &&
                                ((MemberExpression)left.Right).Member == SingleCall.DataSetIdField &&
                                ((MemberExpression)right.Left).Member == SingleCall.DataSetIdField)
                            {
                                startDataSetID = (int)GetConstantValue(left.Left);
                                endDataSetID   = (int)GetConstantValue(right.Right);
                            }
                            else
                            {
                                allIsSafe = false;
                            }
                        }
                        else
                        {
                            allIsSafe = false;
                        }
                    }
                    else
                    {
                        allIsSafe = false;
                    }
                }
                if (allIsSafe)
                {
                    if (newConditions.Count > 0)
                    {
                        return(new Filter(new AllFunctions(startDataSetID, endDataSetID), newConditions.ToArray()));
                    }
                    else
                    {
                        return(new AllFunctions(startDataSetID, endDataSetID));
                    }
                }
            }
            return(new MergeByName(target));
        }