private int ReportError([NotNull] IRow row, [NotNull] IPolyline consecutiveErrorSegments) { var segments = (ISegmentCollection)consecutiveErrorSegments; int segmentCount = segments.SegmentCount; string description; string issueCode; if (GroupIssuesBySegmentType) { esriGeometryType geometryType = segments.Segment[0].GeometryType; SegmentTypeInfo segmentType = _segmentTypes[geometryType]; description = segmentCount > 1 ? string.Format("{0} consecutive {1} segments", segmentCount, segmentType.Description.ToLower()) : string.Format("{0} segment", segmentType.Description); issueCode = segmentType.IssueCode; } else { description = segmentCount > 1 ? string.Format("{0} consecutive non-linear segments", segmentCount) : "Non-linear segment"; issueCode = Code.NonLinearSegments; } // use from point of sequence as error geometry, if Simplify caused the // polyline to become empty (short segments) IGeometry errorGeometry = GetErrorGeometry(consecutiveErrorSegments); return(ReportError(description, errorGeometry, Codes[issueCode], _shapeFieldName, row)); }
/// <summary>Handles member access.</summary> /// <param name="instance">Instance being accessed.</param> /// <returns>The parsed expression.</returns> private Expression ParseMemberAccess(Expression instance) { Debug.Assert(instance != null, "instance != null"); Type type = instance.Type; int errorPos = this.lexer.Position; string id = this.CurrentToken.GetIdentifier(); this.lexer.NextToken(); // Disallow the member access for a collection property. Debug.Assert(this.currentSegmentInfo != null, "Must have initialized current segment information."); if (this.currentSegmentInfo.IsCollection) { throw ParseError(Strings.RequestQueryParser_UnknownProperty(id, WebUtil.GetTypeName(type), errorPos)); } // An open paren here would indicate calling a method in regular C# syntax. ResourceProperty property = this.currentSegmentInfo.ResourceType == null ? null : // null means the current segment was already an open type this.currentSegmentInfo.ResourceType.TryResolvePropertyName(id); ResourceSetWrapper container = this.currentSegmentInfo.ResourceSet == null || property == null || property.TypeKind != ResourceTypeKind.EntityType ? null : this.provider.GetContainer(this.currentSegmentInfo.ResourceSet, this.currentSegmentInfo.ResourceType, property); if (property != null) { if (property.TypeKind == ResourceTypeKind.EntityType && container == null) { throw DataServiceException.CreateBadRequestError(Strings.BadRequest_InvalidPropertyNameSpecified(id, this.currentSegmentInfo.ResourceType.FullName)); } // We have a strongly-type property. Expression propertyAccess; if (property.CanReflectOnInstanceTypeProperty) { propertyAccess = Expression.Property(instance, this.currentSegmentInfo.ResourceType.GetPropertyInfo(property)); } else { // object DataServiceProviderMethods.GetValue(object, ResourceProperty) propertyAccess = Expression.Call( null, /*instance*/ DataServiceProviderMethods.GetValueMethodInfo, instance, Expression.Constant(property)); propertyAccess = Expression.Convert(propertyAccess, property.Type); } Expression result = this.ConsiderNullPropagation(instance, propertyAccess); if (container != null) { bool singleResult = property.Kind == ResourcePropertyKind.ResourceReference; DataServiceConfiguration.CheckResourceRightsForRead(container, singleResult); Expression filter = DataServiceConfiguration.ComposeQueryInterceptors(this.service, container); if (filter != null) { // We did null propagation for accessing the property, but we may also need // to do null propagation on the property value itself (otherwise the interception // lambda needs to check the argument for null, which is probably unexpected). result = RequestQueryProcessor.ComposePropertyNavigation( result, (LambdaExpression)filter, this.provider.NullPropagationRequired); } } this.currentSegmentInfo = new SegmentTypeInfo( property.ResourceType, container, property.Kind == ResourcePropertyKind.ResourceSetReference); return result; } else { ResourceType resourceType = this.currentSegmentInfo.ResourceType; this.currentSegmentInfo = new SegmentTypeInfo(null, null, false); // Open types can have any members inside them if (resourceType == null || resourceType.IsOpenType) { // object OpenTypeMethods.GetValue(object, string) Expression call = Expression.Call(null /* instance */, OpenTypeMethods.GetValueOpenPropertyMethodInfo, instance, Expression.Constant(id)); return this.ConsiderNullPropagation(instance, call); } else { throw ParseError(Strings.RequestQueryParser_UnknownProperty(id, WebUtil.GetTypeName(type), errorPos)); } } }
/// <summary>Handles identifiers which have been recognized as functions.</summary> /// <returns>The parsed expression.</returns> private Expression ParseIdentifierAsFunction() { FunctionDescription[] functionDescriptions; Token functionToken = this.CurrentToken; if (!functions.TryGetValue(functionToken.Text, out functionDescriptions)) { throw ParseError(Strings.RequestQueryParser_UnknownFunction(functionToken.Text, functionToken.Position)); } if (!this.service.Configuration.DataServiceBehavior.AcceptReplaceFunctionInQuery && functionDescriptions[0].IsReplace) { throw ParseError(Strings.RequestQueryParser_UnknownFunction(functionToken.Text, functionToken.Position)); } this.lexer.NextToken(); Expression[] originalArguments = this.ParseArgumentList(); Expression[] arguments = this.nullPropagationRequired ? originalArguments : (Expression[])originalArguments.Clone(); Expression candidateTypeArgument = arguments.Length > 1 ? arguments[1] : arguments.Length > 0 ? arguments[0] : null; // check if the one of the parameters is of open type. If yes, then we need to invoke // LateBoundMethods for this function otherwise not. bool openParameters = false; if (!functionDescriptions[0].IsTypeCast && !functionDescriptions[0].IsTypeCheck) { foreach (Expression argument in arguments) { if (IsOpenPropertyExpression(argument)) { openParameters = true; break; } } } Expression result = null; FunctionDescription function = null; if (openParameters) { foreach (FunctionDescription functionDescription in functionDescriptions) { if (functionDescription.ParameterTypes.Length == arguments.Length) { function = functionDescription; break; } } Expression[] openArguments = new Expression[arguments.Length]; for (int i = 0; i < openArguments.Length; i++) { if (IsOpenPropertyExpression(arguments[i])) { openArguments[i] = arguments[i]; } else { openArguments[i] = Expression.Convert(arguments[i], typeof(object)); } } if (function == null) { string message = Strings.RequestQueryParser_NoApplicableFunction( functionToken.Text, functionToken.Position, FunctionDescription.BuildSignatureList(functionToken.Text, functionDescriptions)); throw ParseError(message); } result = function.InvokeOpenTypeMethod(openArguments); } else { function = this.FindBestFunction(functionDescriptions, ref arguments); if (function == null) { string message = Strings.RequestQueryParser_NoApplicableFunction( functionToken.Text, functionToken.Position, FunctionDescription.BuildSignatureList(functionToken.Text, functionDescriptions)); throw ParseError(message); } // Special case for null propagation - we never strip nullability from expressions. if (this.nullPropagationRequired && function.IsTypeCast) { Expression typeExpression = arguments[arguments.Length - 1]; Debug.Assert(typeExpression != null, "typeExpression != null -- otherwise function finding failed."); if (typeExpression.Type == typeof(Type)) { Type castTargetType = (Type)((ConstantExpression)typeExpression).Value; if (!WebUtil.TypeAllowsNull(castTargetType)) { arguments[arguments.Length - 1] = Expression.Constant(typeof(Nullable<>).MakeGenericType(castTargetType)); } } } Expression[] finalArguments; if (function.ConversionFunction == FunctionDescription.BinaryIsOfResourceType || function.ConversionFunction == FunctionDescription.BinaryCastResourceType) { finalArguments = new Expression[arguments.Length + 1]; for (int i = 0; i < arguments.Length; i++) { finalArguments[i] = arguments[i]; } finalArguments[arguments.Length] = Expression.Constant(IsOpenPropertyExpression(arguments[0]), typeof(bool)); } else { finalArguments = arguments; } result = function.ConversionFunction(this.it, finalArguments); } if (this.nullPropagationRequired && !function.IsTypeCheck && !function.IsTypeCast) { Debug.Assert( originalArguments.Length == arguments.Length, "originalArguments.Length == arguments.Length -- arguments should not be added/removed"); for (int i = 0; i < originalArguments.Length; i++) { result = this.ConsiderNullPropagation(originalArguments[i], result); } } // type casts change the type of the "current" item, reflect this in parser state if (function.IsTypeCast) { Debug.Assert(candidateTypeArgument != null, "Should have failed to bind to the function if arguments don't match"); Debug.Assert(candidateTypeArgument.Type == typeof(string), "First argument to 'cast' should have been a string"); Debug.Assert(candidateTypeArgument.NodeType == ExpressionType.Constant, "Non-constant in type name for a cast?"); this.currentSegmentInfo = new SegmentTypeInfo( WebUtil.TryResolveResourceType(this.provider, (string)((ConstantExpression)candidateTypeArgument).Value), this.currentSegmentInfo != null ? this.currentSegmentInfo.ResourceSet : this.setForIt, this.currentSegmentInfo != null ? this.currentSegmentInfo.IsCollection : false); } return result; }
/// <summary>Handles identifiers.</summary> /// <returns>The parsed expression.</returns> private Expression ParseIdentifier() { this.ValidateToken(TokenId.Identifier); // An open paren here would indicate calling a method in regular C# syntax. bool identifierIsFunction = this.lexer.PeekNextToken().Id == TokenId.OpenParen; if (identifierIsFunction) { return this.ParseIdentifierAsFunction(); } else { this.currentSegmentInfo = new SegmentTypeInfo(this.typeForIt, this.setForIt, false); return this.ParseMemberAccess(this.it); } }