예제 #1
0
        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);
                }
            }