private void FinishNodes(ParamTreeNode current)
 {
     current.FinishNode();
     foreach (ParamTreeNode node in current.Children)
     {
         FinishNodes(node);
     }
 }
 public void Walk(int param, ParamTreeNode node)
 {
     for (int i = 0; i < param + 1; i++)
     {
         Write("    ");
     }
     WriteLine(String.Format("{0} {1}", node.ParamType, node.Flags));
 }
        public void AddMethod(MethodTracker method)
        {
#if DEBUG
            if (fFinished)
            {
                throw new InvalidOperationException("Cannot add methods to finished param trees");
            }
#endif

            ParamTreeNode   curNode   = this;
            ParameterInfo[] pis       = method.GetParameters();
            bool            fIsParams = false;

            if (pis.Length > 0 && ReflectionUtil.IsParamArray(pis[pis.Length - 1]))
            {
                fIsParams = true;
            }

            if (!method.IsStatic)
            {
                Type instType = method.DeclaringType;
                if ((funcType & FunctionType.FunctionMethodMask) == FunctionType.FunctionMethodMask)
                {
                    instType = typeof(InstanceArgument);
                }

                curNode = curNode.AppendChild(method, instType, NodeFlags.None, argumentCount == 1);
                AppendParameters(method, curNode, pis, fIsParams, 1, 0);
            }
            else
            {
                int depthStart = 0;
                if ((funcType & FunctionType.OpsFunction) != 0 &&
                    (funcType & FunctionType.FunctionMethodMask) == FunctionType.FunctionMethodMask)
                {
                    // this is an ops function that is combined w/ an ops method.  We need to support
                    // disambiguating between bound & unbound method calls, so we transform arg 1
                    // to an instance just like we do for non-static functions, and then skip the 1st
                    // parameter in AppendParameters.  In either case we want both depths to
                    // start at 1 (we're appending @ depth 1, and reading from param 1 because we've
                    // used param 0) so we just use depthStart here for both.
                    depthStart = 1;
                    curNode    = curNode.AppendChild(method, typeof(InstanceArgument), NodeFlags.None, argumentCount == 1);
                }

                AppendParameters(method, curNode, pis, fIsParams, depthStart, depthStart);
            }

            Methods.Add(method);
        }
        private void WalkWorker(IParamWalker callback, ParamTreeNode curNode, int depth)
        {
            callback.Walk(depth, curNode);

            if (curNode.Children.Count != 0)
            {
                callback.PreArgument(depth + 1, curNode.Children.Count);

                for (int i = 0; i < curNode.Children.Count; i++)
                {
                    WalkWorker(callback, curNode.Children[i], depth + 1);
                }

                callback.PostArgument(depth + 1);
            }
        }
        public ParamTreeNode AppendChild(MethodTracker method, Type curType, ParamTree.NodeFlags flags, bool fLastArg)
        {
            bool          fFound = false;
            ParamTreeNode res    = this;

            for (int i = 0; i < Children.Count; i++)
            {
                if (Children[i].ParamType == curType && Children[i].Flags == flags)
                {
                    res = Children[i];
                    res.Methods.Add(method);
                    fFound = true;
                    break;
                }
            }

            if (!fFound)
            {
                res = InsertNewNode(curType, flags);
                res.Methods.Add(method);
            }
            else if (fLastArg)
            {
                // last node, we shouldn't be adding
                // extra methods here.  We have two ways
                // we get here:
                //  1. We have a static and non-static overload, prefer the instance method
                //  2. We have default values for one of the methods, prefer the one w/o defaults.
                //
                // Both of these are identical checks: We prefer the method w/ less parameters.

                Debug.Assert(res.Methods.Count == 2);

                if (method.GetParameters().Length < res.Methods[0].GetParameters().Length)
                {
                    // remove the old one.
                    res.Methods.RemoveAt(0);
                }
                else
                {
                    // remove the new one.
                    res.Methods.RemoveAt(1);
                }
            }

            return(res);
        }
        private void AppendParameters(MethodTracker method, ParamTreeNode curNode, ParameterInfo[] pis, bool fIsParams, int depthStart, int pisStart)
        {
            int argCnt = argumentCount;

            for (int i = depthStart; i < argCnt; i++)
            {
                NodeFlags flags;
                Type      curType = GetCurrentType(pis, i - depthStart + pisStart, fIsParams, out flags);

                if ((flags & NodeFlags.Out) != 0 && (i - depthStart + pisStart) < pis.Length)
                {
                    // got an out param, need one more argument still...
                    argCnt++;
                }

                bool fLastArg = (i == argumentCount - 1);

                curNode = curNode.AppendChild(method, curType, flags, fLastArg);
            }
        }
        private ParamTreeNode InsertNewNode(Type newNodeType, ParamTree.NodeFlags flags)
        {
            ParamTreeNode newNode = new ParamTreeNode(newNodeType, flags);

            if (newNodeType != null)
            {
                // we've made the node, use the element type for the checks below...
                if (newNodeType.IsByRef)
                {
                    newNodeType = newNodeType.GetElementType();
                }

                // insert based upon subclassing order (if we're a subclass
                // of someone we need to come first). When we walk the tree we'll
                // then emit checks for more specific types before less specific types.

                OpsReflectedType newDt          = Ops.GetDynamicTypeFromType(newNodeType) as OpsReflectedType;
                Type             extensibleType = null;
                if (newDt != null)
                {
                    extensibleType = newDt.GetTypeToExtend();
                }

                if (newNodeType != typeof(object))
                {
                    for (int i = 0; i < Children.Count; i++)
                    {
                        Type childParamType = Children[i].ParamType;

                        if (childParamType == null)
                        {
                            // params method w/ mixed levels, no subclasses checks to be done.
                            continue;
                        }

                        if (childParamType.IsByRef)
                        {
                            childParamType = childParamType.GetElementType();
                        }

                        // extensible types are logically subclasses of their "parent" type, and
                        // therefore their check needs to go first.  If extensible is added first
                        // then the real type will come next automatically, otherwise we'll
                        // check for the type here & early out if we're adding the extensible type.
                        if (newNodeType == extensibleType && childParamType == newDt.type)
                        {
                            Children.Insert(i, newNode);
                            return(newNode);
                        }

                        if (newNodeType.IsSubclassOf(childParamType) ||
                            (newNodeType.IsClass && childParamType.IsInterface))        // classes before interfaces
                        {
                            Children.Insert(i, newNode);
                            return(newNode);
                        }
                    }
                }
            }

            Children.Add(newNode);

            return(newNode);
        }