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); }