/// <summary> /// Builds a MethodContext object based on the given method element. /// </summary> /// <param name="methodTag">An XElement representing the method to build the context for. This can be either a function, constructor or destructor element.</param> /// <returns>A MethodContext object based on the given method.</returns> /// <exception cref="System.ArgumentException">The passed XElement does not represent a function, constructor, or destructor element.</exception> /// <exception cref="System.ArgumentNullException">methodTag is null.</exception> public static MethodContext BuildMethodContext(XElement methodTag) { if (methodTag == null) { throw new ArgumentNullException("methodTag"); } else if (!(methodTag.Name == SRC.Function || methodTag.Name == SRC.Constructor || methodTag.Name == SRC.Destructor)) { throw new ArgumentException(string.Format("The passed XElement must represent a <function>, <constructor> or <destructor> element. Received a <{0}> element.", methodTag.Name.ToString()), "methodTag"); } MethodContext mc = new MethodContext(); //set return type if (methodTag.Name == SRC.Function) { bool isPrimitive; mc.IdType = ConstructTypeName(methodTag.Element(SRC.Type), out isPrimitive); mc.IdTypeIsPrimitive = isPrimitive; } //record if constructor if (methodTag.Name == SRC.Constructor) { mc.IsConstructor = true; } //record if destructor if (methodTag.Name == SRC.Destructor) { mc.IsDestructor = true; } //record if static //look for the static keyword (at the function definition) //This is not entirely sufficient because it's possible for the static keyword to be present at only the function declaration and not the definition //Also, some other word may be #defined to static and used instead var typeElement = methodTag.Element(SRC.Type); if (typeElement != null) { foreach (var typeNameTag in typeElement.Elements(SRC.Name)) { if (typeNameTag.Value.Equals("static", StringComparison.InvariantCultureIgnoreCase)) { mc.IsStatic = true; break; } } } //formal parameters mc.FormalParameters = new List <FormalParameterRecord>(); XElement paramList = methodTag.Element(SRC.ParameterList); if (paramList != null) { foreach (var param in paramList.Elements(SRC.Parameter)) { //a param (usually) looks like: <param><decl><type><name>...</name></type> <name>...</name></decl></param> string type = string.Empty; string name = string.Empty; bool isPrimitive = false; var declElement = param.Element(SRC.Declaration); if (declElement != null && declElement.Element(SRC.Type) != null) { type = ConstructTypeName(declElement.Element(SRC.Type), out isPrimitive); } if (declElement != null && declElement.Element(SRC.Name) != null) { name = param.Element(SRC.Declaration).Element(SRC.Name).Value; } //add parameter, if it's valid if (!(string.IsNullOrEmpty(type) && string.IsNullOrEmpty(name)) && type != "void") { mc.FormalParameters.Add(new FormalParameterRecord(type, isPrimitive, name)); } } } //Determine declaring class XElement classNameTag = SrcMLElement.GetClassNameForMethod(methodTag); if (classNameTag != null) { //class name listed with method name: <ClassName>::<MethodName> mc.DeclaringClass = classNameTag.Value; } else if (classNameTag == null && mc.IsConstructor) { //class name not listed, but the method is a constructor //I'm not sure if this is actually possible mc.DeclaringClass = SrcMLElement.GetNameForMethod(methodTag).Value; } else if (classNameTag == null) { //no class name listed, but this might be an inline method in the class declaration //search for the enclosing <class> or <struct> tag XElement classElement = FindEnclosingClassElement(methodTag); if (classElement != null && classElement.Element(SRC.Name) != null) { mc.DeclaringClass = GetNameFromNameElement(classElement.Element(SRC.Name)); } } return(mc); }