internal override Expression VisitMemberAccess(MemberExpression m) { PropertyInfo info; Expression expression; Type type = m.Expression.Type; this.leafExpressionIsMemberAccess = true; if (PrimitiveType.IsKnownNullableType(type)) { this.leafExpressionIsMemberAccess = false; return(base.VisitMemberAccess(m)); } if (ProjectionAnalyzer.IsCollectionProducingExpression(m.Expression)) { throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } if (!ResourceBinder.PatternRules.MatchNonPrivateReadableProperty(m, out info, out expression)) { throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } Expression expression2 = base.VisitMemberAccess(m); if (ClientTypeUtil.TypeOrElementTypeIsEntity(type)) { Type type2; ResourceBinder.StripTo <Expression>(m.Expression, out type2); this.box.AppendPropertyToPath(info, type2, this.context); this.leafExpressionIsMemberAccess = false; } return(expression2); }
internal override Expression VisitMethodCall(MethodCallExpression m) { Expression expressionBeforeNormalization = this.GetExpressionBeforeNormalization(m); if (expressionBeforeNormalization != m) { return(this.Visit(expressionBeforeNormalization)); } if (this.pathBuilder.CurrentIsEntity) { if (m.Method.Name == "Select") { return(this.RebindMethodCallForMemberSelect(m)); } if (m.Method.Name == "ToList") { return(this.RebindMethodCallForMemberToList(m)); } return(base.VisitMethodCall(m)); } if (ProjectionAnalyzer.IsMethodCallAllowedEntitySequence(m)) { return(this.RebindMethodCallForNewSequence(m)); } return(base.VisitMethodCall(m)); }
internal override Expression VisitTypeIs(TypeBinaryExpression b) { if (ClientTypeUtil.TypeOrElementTypeIsEntity(b.Expression.Type) || ProjectionAnalyzer.IsCollectionProducingExpression(b.Expression)) { throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, b.ToString())); } return(base.VisitTypeIs(b)); }
private static void AnalyzeResourceExpression(LambdaExpression lambda, ResourceExpression resource) { PathBox pb = new PathBox(); ProjectionAnalyzer.Analyze(lambda, pb); resource.Projection = new ProjectionQueryOptionExpression(lambda.Body.Type, lambda, pb.ProjectionPaths.ToList()); resource.ExpandPaths = pb.ExpandPaths.Union(resource.ExpandPaths, StringComparer.Ordinal).ToList(); }
internal override Expression VisitMemberInit(MemberInitExpression init) { if (!ClientTypeUtil.TypeOrElementTypeIsEntity(init.Type)) { throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, init.ToString())); } ProjectionAnalyzer.Analyze(init, this.box, this.context); return(init); }
/// <summary> /// Analyzes the specified <paramref name="lambda"/> for selection and updates /// <paramref name="resource"/>. /// </summary> /// <param name="lambda">Lambda expression to analyze.</param> /// <param name="resource">Resource expression to update.</param> /// <param name="context">Context of expression to analyze.</param> private static void AnalyzeResourceExpression(LambdaExpression lambda, ResourceExpression resource, DataServiceContext context) { PathBox pb = new PathBox(); ProjectionAnalyzer.Analyze(lambda, pb, context); resource.Projection = new ProjectionQueryOptionExpression(lambda.Body.Type, lambda, pb.ProjectionPaths.ToList()); resource.ExpandPaths = pb.ExpandPaths.Union(resource.ExpandPaths, StringComparer.Ordinal).ToList(); resource.RaiseUriVersion(pb.UriVersion); }
private Expression RebindMethodCallForNewSequence(MethodCallExpression call) { Debug.Assert(call != null, "call != null"); Debug.Assert(ProjectionAnalyzer.IsMethodCallAllowedEntitySequence(call), "ProjectionAnalyzer.IsMethodCallAllowedEntitySequence(call)"); Debug.Assert(call.Object == null, "call.Object == null -- otherwise this isn't the supported Select or ToList methods"); Expression result = null; if (call.Method.Name == "Select") { Debug.Assert(call.Arguments.Count == 2, "call.Arguments.Count == 2 -- otherwise this isn't the argument we expected"); Expression parameterSource = this.Visit(call.Arguments[0]); ExpressionAnnotation annotation; this.annotations.TryGetValue(parameterSource, out annotation); if (annotation != null) { Expression selectorExpression = this.Visit(call.Arguments[1]); Type returnElementType = call.Method.ReturnType.GetGenericArguments()[0]; result = CallMaterializer( "ProjectionSelect", this.materializerExpression, this.pathBuilder.ParameterEntryInScope, this.pathBuilder.ExpectedParamTypeInScope, Expression.Constant(returnElementType, typeof(Type)), Expression.Constant(annotation.Segment.StartPath, typeof(object)), selectorExpression); this.annotations.Add(result, annotation); result = CallMaterializerWithType( "EnumerateAsElementType", new Type[] { returnElementType }, result); this.annotations.Add(result, annotation); } } else { Debug.Assert(call.Method.Name == "ToList", "call.Method.Name == 'ToList'"); Expression source = this.Visit(call.Arguments[0]); ExpressionAnnotation annotation; if (this.annotations.TryGetValue(source, out annotation)) { result = this.TypedEnumerableToList(source, call.Type); this.annotations.Add(result, annotation); } } if (result == null) { result = base.VisitMethodCall(call); } return(result); }
internal override Expression VisitMemberInit(MemberInitExpression init) { if (!ClientTypeUtil.TypeOrElementTypeIsEntity(init.Type)) { // MemberInit to a complex type is not supported on entity types. throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, init.ToString())); } ProjectionAnalyzer.Analyze(init, this.box, this.context); return(init); }
internal override Expression VisitMethodCall(MethodCallExpression m) { if (((m.Object != null) && ProjectionAnalyzer.IsDisallowedExpressionForMethodCall(m.Object, this.context.MaxProtocolVersion)) || m.Arguments.Any <Expression>(a => ProjectionAnalyzer.IsDisallowedExpressionForMethodCall(a, this.context.MaxProtocolVersion))) { throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } ProjectionAnalyzer.CheckChainedSequence(m, this.type); if (!ProjectionAnalyzer.IsMethodCallAllowedEntitySequence(m) && (((m.Object != null) ? ClientTypeUtil.TypeOrElementTypeIsEntity(m.Object.Type) : false) || m.Arguments.Any <Expression>(a => ClientTypeUtil.TypeOrElementTypeIsEntity(a.Type)))) { throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } return(base.VisitMethodCall(m)); }
internal override Expression VisitInvocation(InvocationExpression iv) { if ((ClientTypeUtil.TypeOrElementTypeIsEntity(iv.Expression.Type) || ProjectionAnalyzer.IsCollectionProducingExpression(iv.Expression)) || iv.Arguments.Any <Expression>(delegate(Expression a) { if (!ClientTypeUtil.TypeOrElementTypeIsEntity(a.Type)) { return(ProjectionAnalyzer.IsCollectionProducingExpression(a)); } return(true); })) { throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, iv.ToString())); } return(base.VisitInvocation(iv)); }
internal override Expression VisitMethodCall(MethodCallExpression m) { if ((m.Object != null && IsDisallowedExpressionForMethodCall(m.Object)) || m.Arguments.Any(a => IsDisallowedExpressionForMethodCall(a))) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } if (ProjectionAnalyzer.IsMethodCallAllowedEntitySequence(m)) { CheckChainedSequence(m, this.type); return(base.VisitMethodCall(m)); } throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, m.ToString())); }
internal override Expression VisitMethodCall(MethodCallExpression m) { Debug.Assert(m != null, "m != null"); Expression original = this.GetExpressionBeforeNormalization(m); if (original != m) { return(this.Visit(original)); } Expression result; if (this.pathBuilder.CurrentIsEntity) { Debug.Assert( ProjectionAnalyzer.IsMethodCallAllowedEntitySequence(m) || ResourceBinder.PatternRules.MatchReferenceEquals(m), "ProjectionAnalyzer.IsMethodCallAllowedEntitySequence(m) || ResourceBinder.PatternRules.MatchReferenceEquals(m) -- otherwise ProjectionAnalyzer should have blocked this for entities"); if (m.Method.Name == "Select") { result = this.RebindMethodCallForMemberSelect(m); } else if (m.Method.Name == "ToList") { result = this.RebindMethodCallForMemberToList(m); } else { Debug.Assert(m.Method.Name == "ReferenceEquals", "We don't know how to handle this method, ProjectionAnalyzer updated?"); result = base.VisitMethodCall(m); } } else { if (ProjectionAnalyzer.IsMethodCallAllowedEntitySequence(m)) { result = this.RebindMethodCallForNewSequence(m); } else { result = base.VisitMethodCall(m); } } return(result); }
internal override Expression VisitMethodCall(MethodCallExpression m) { if ((m.Object != null && IsDisallowedExpressionForMethodCall(m.Object)) || m.Arguments.Any(a => IsDisallowedExpressionForMethodCall(a))) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } if (ProjectionAnalyzer.IsMethodCallAllowedEntitySequence(m)) { CheckChainedSequence(m, this.type); // allow selects for following pattern: // Orders = c.Orders.Select(o=> new NarrowOrder {...}).ToList(); return(base.VisitMethodCall(m)); } throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, m.ToString())); }
internal override Expression VisitMethodCall(MethodCallExpression m) { // We throw NotSupportedException when IsDisallowedExceptionForMethodCall() is true // or we have a method call on a non-entity type, for example c.MyCollectionComplexProperty.Select(...) if ((m.Object != null && (IsDisallowedExpressionForMethodCall(m.Object, this.context.Model) || !ClientTypeUtil.TypeOrElementTypeIsEntity(m.Object.Type))) || m.Arguments.Any(a => IsDisallowedExpressionForMethodCall(a, this.context.Model)) || (m.Object == null && !ClientTypeUtil.TypeOrElementTypeIsEntity(m.Arguments[0].Type))) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } if (ProjectionAnalyzer.IsMethodCallAllowedEntitySequence(m)) { CheckChainedSequence(m, this.type); // allow selects for following pattern: // Orders = c.Orders.Select(o=> new NarrowOrder {...}).ToList(); return(base.VisitMethodCall(m)); } throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjectionToEntity(this.type, m.ToString())); }
internal override Expression VisitMethodCall(MethodCallExpression m) { if ((m.Object != null && IsDisallowedExpressionForMethodCall(m.Object, this.context.Model)) || m.Arguments.Any(a => IsDisallowedExpressionForMethodCall(a, this.context.Model))) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } CheckChainedSequence(m, this.type); if (ProjectionAnalyzer.IsMethodCallAllowedEntitySequence(m)) { // allow IEnum.Select and IEnum.ToList even if entity type. return(base.VisitMethodCall(m)); } if ((m.Object != null ? ClientTypeUtil.TypeOrElementTypeIsEntity(m.Object.Type) : false) || m.Arguments.Any(a => ClientTypeUtil.TypeOrElementTypeIsEntity(a.Type))) { throw new NotSupportedException(Strings.ALinq_ExpressionNotSupportedInProjection(this.type, m.ToString())); } return(base.VisitMethodCall(m)); }
internal override Expression VisitUnary(UnaryExpression u) { UnaryExpression expression = (UnaryExpression)base.VisitUnary(u); Expression rewritten = expression; this.RecordRewrite(u, rewritten); if ((expression.NodeType != ExpressionType.Convert) && (expression.NodeType != ExpressionType.TypeAs)) { return(rewritten); } if (!expression.Type.IsAssignableFrom(expression.Operand.Type)) { return(rewritten); } if ((PrimitiveType.IsKnownNullableType(expression.Operand.Type) || PrimitiveType.IsKnownNullableType(expression.Type)) && !(expression.Operand.Type == expression.Type)) { return(rewritten); } if (ClientTypeUtil.TypeOrElementTypeIsEntity(expression.Operand.Type) && ProjectionAnalyzer.IsCollectionProducingExpression(expression.Operand)) { return(rewritten); } return(expression.Operand); }
internal override Expression VisitLambda(LambdaExpression lambda) { ProjectionAnalyzer.Analyze(lambda, this.box); return(lambda); }
/// <summary> /// CODE: x /// ORIGINAL: Convert(x, t) where t is assignable from typeof(x) /// ORIGINAL: x as t, where t is assignable from typeof(x) /// ORIGINAL: and typeof(x) or t are not known primitives unless typeof(x) == t /// ORIGINAL: and x is not a collection of entity types /// NORMALIZED: x /// </summary> internal override Expression VisitUnary(UnaryExpression u) { UnaryExpression visited = (UnaryExpression)base.VisitUnary(u); Expression result = visited; // Note that typically we would record a potential rewrite // after extracting the conversion, but we avoid doing this // because it breaks undoing the rewrite by making the non-local // change circular, ie: // unary [operand = a] // becomes // a <- unary [operand = a] // So the undoing visits a, then the original unary, then the // operand and again the unary, the operand, etc. this.RecordRewrite(u, result); // Convert(x, t) or x as t, where t is assignable from typeof(x) if ((visited.NodeType == ExpressionType.Convert || visited.NodeType == ExpressionType.TypeAs) && visited.Type.IsAssignableFrom(visited.Operand.Type)) { // typeof(x) or t are not known primitives unless typeof(x) == t if (!ClientConvert.IsKnownNullableType(visited.Operand.Type) && !ClientConvert.IsKnownNullableType(visited.Type) || visited.Operand.Type == visited.Type) { // x is not a collection of entity types if (!(ClientType.CheckElementTypeIsEntity(visited.Operand.Type) && ProjectionAnalyzer.IsCollectionProducingExpression(visited.Operand))) { result = visited.Operand; } } } return(result); }
internal override Expression VisitUnary(UnaryExpression u) { UnaryExpression visited = (UnaryExpression)base.VisitUnary(u); Expression result = visited; this.RecordRewrite(u, result); if ((visited.NodeType == ExpressionType.Convert || visited.NodeType == ExpressionType.TypeAs) && visited.Type.IsAssignableFrom(visited.Operand.Type)) { if (!ClientConvert.IsKnownNullableType(visited.Operand.Type) && !ClientConvert.IsKnownNullableType(visited.Type) || visited.Operand.Type == visited.Type) { if (!(ClientType.CheckElementTypeIsEntity(visited.Operand.Type) && ProjectionAnalyzer.IsCollectionProducingExpression(visited.Operand))) { result = visited.Operand; } } } return(result); }
internal override Expression VisitMemberInit(MemberInitExpression init) { ProjectionAnalyzer.Analyze(init, this.box); return(init); }
internal override Expression VisitConditional(ConditionalExpression c) { ResourceBinder.PatternRules.MatchNullCheckResult result = ResourceBinder.PatternRules.MatchNullCheck(this.box.ParamExpressionInScope, c); if (result.Match) { this.Visit(result.AssignExpression); return(c); } if (((ClientTypeUtil.TypeOrElementTypeIsEntity(c.Test.Type) || ClientTypeUtil.TypeOrElementTypeIsEntity(c.IfTrue.Type)) || (ClientTypeUtil.TypeOrElementTypeIsEntity(c.IfFalse.Type) || ProjectionAnalyzer.IsCollectionProducingExpression(c.Test))) || (ProjectionAnalyzer.IsCollectionProducingExpression(c.IfTrue) || ProjectionAnalyzer.IsCollectionProducingExpression(c.IfFalse))) { throw new NotSupportedException(System.Data.Services.Client.Strings.ALinq_ExpressionNotSupportedInProjection(this.type, c.ToString())); } return(base.VisitConditional(c)); }