Ejemplo n.º 1
0
        /// <summary>
        /// Finds the signature that best matches the arguments
        /// </summary>
        /// <param name="functionName">The name of the function</param>
        /// <param name="argumentNodes">The nodes of the arguments, can be new {null,null}.</param>
        /// <param name="signatures">The signatures to match against</param>
        /// <returns>Returns the matching signature or throws</returns>
        internal static FunctionSignatureWithReturnType MatchSignatureToBuiltInFunction(string functionName, SingleValueNode[] argumentNodes, FunctionSignatureWithReturnType[] signatures)
        {
            FunctionSignatureWithReturnType signature;
            IEdmTypeReference[] argumentTypes = argumentNodes.Select(s => s.TypeReference).ToArray();

            // Handle the cases where we don't have type information (null literal, open properties) for ANY of the arguments
            int argumentCount = argumentTypes.Length;
            if (argumentTypes.All(a => a == null) && argumentCount > 0)
            {
                // we specifically want to find just the first function that matches the number of arguments, we don't care about
                // ambiguity here because we're already in an ambiguous case where we don't know what kind of types 
                // those arguments are.
                signature = signatures.FirstOrDefault(candidateFunction => candidateFunction.ArgumentTypes.Count() == argumentCount);
                if (signature == null)
                {
                    throw new ODataException(ODataErrorStrings.FunctionCallBinder_CannotFindASuitableOverload(functionName, argumentTypes.Count()));
                }
                else
                {
                    // in this case we can't assert the return type, we can only assert that a function exists... so 
                    // we need to set the return type to null.
                    signature = new FunctionSignatureWithReturnType(null, signature.ArgumentTypes);
                }
            }
            else
            {
                signature = TypePromotionUtils.FindBestFunctionSignature(signatures, argumentNodes);
                if (signature == null)
                {
                    throw new ODataException(ODataErrorStrings.MetadataBinder_NoApplicableFunctionFound(
                        functionName,
                        BuiltInFunctions.BuildFunctionSignatureListDescription(functionName, signatures)));
                }
            }

            return signature;
        }
Ejemplo n.º 2
0
        /// <summary>Finds the best fitting function for the specified arguments.</summary>
        /// <param name="functions">Functions to consider.</param>
        /// <param name="argumentNodes">Nodes of the arguments for the function, can be new {null,null}.</param>
        /// <returns>The best fitting function; null if none found or ambiguous.</returns>
        internal static FunctionSignatureWithReturnType FindBestFunctionSignature(FunctionSignatureWithReturnType[] functions, SingleValueNode[] argumentNodes)
        {
            IEdmTypeReference[] argumentTypes = argumentNodes.Select(s => s.TypeReference).ToArray();
            Debug.Assert(functions != null, "functions != null");
            Debug.Assert(argumentTypes != null, "argumentTypes != null");
            List<FunctionSignatureWithReturnType> applicableFunctions = new List<FunctionSignatureWithReturnType>(functions.Length);

            // Build a list of applicable functions (and cache their promoted arguments).
            foreach (FunctionSignatureWithReturnType candidate in functions)
            {
                if (candidate.ArgumentTypes.Length != argumentTypes.Length)
                {
                    continue;
                }

                bool argumentsMatch = true;
                for (int i = 0; i < candidate.ArgumentTypes.Length; i++)
                {
                    if (!CanPromoteNodeTo(argumentNodes[i], argumentTypes[i], candidate.ArgumentTypes[i]))
                    {
                        argumentsMatch = false;
                        break;
                    }
                }

                if (argumentsMatch)
                {
                    applicableFunctions.Add(candidate);
                }
            }

            // Return the best applicable function.
            if (applicableFunctions.Count == 0)
            {
                // No matching function.
                return null;
            }
            else if (applicableFunctions.Count == 1)
            {
                return applicableFunctions[0];
            }
            else
            {
                // Find a single function which is better than all others.
                int bestFunctionIndex = -1;
                for (int i = 0; i < applicableFunctions.Count; i++)
                {
                    bool betterThanAllOthers = true;
                    for (int j = 0; j < applicableFunctions.Count; j++)
                    {
                        if (i != j && MatchesArgumentTypesBetterThan(argumentTypes, applicableFunctions[j].ArgumentTypes, applicableFunctions[i].ArgumentTypes))
                        {
                            betterThanAllOthers = false;
                            break;
                        }
                    }

                    if (betterThanAllOthers)
                    {
                        if (bestFunctionIndex == -1)
                        {
                            bestFunctionIndex = i;
                        }
                        else
                        {
                            // This means there were at least 2 equally matching functions.
                            return null;
                        }
                    }
                }

                if (bestFunctionIndex == -1)
                {
                    return null;
                }

                return applicableFunctions[bestFunctionIndex];
            }
        }