/// <summary> /// Parses methods into the dotnet object passed in. /// Expects methods to be empty /// </summary> /// <param name="dotnetObject"></param> public void ParseMethods(DotnetObject dotnetObject) { var dotnetType = dotnetObject.TypeDefinition; var methods = dotnetType.Methods; // loop through base classes while (methods != null) { ParseMethodsOnType(dotnetObject, methods, dotnetType); if (NoInheritedMembers) { break; } var tref = dotnetType.BaseType; if (tref == null || tref.FullName == dotnetType.FullName) { break; } dotnetType = tref.Resolve(); methods = dotnetType.Methods; } }
/// <summary> /// Converts a CLR typename to VB or C# type name. Type must passed in as plain name /// not in full system format. /// </summary> /// <param name="typeName"></param> /// <param name="Language"></param> /// <returns></returns> public static string FixupTypename(TypeDefinition type) { var typeName = FixupStringTypeName(type.Name); if (type.IsGenericInstance || type.IsGenericParameter) { return(DotnetObject.GetGenericTypeName(type.GetElementType(), GenericTypeNameFormats.TypeName)); } return(typeName); }
/// <summary> /// Parses all properties for the type passed /// </summary> /// <param name="dotnetObject"></param> public void ParseEvents(DotnetObject dotnetObject) { var dotnetType = dotnetObject.TypeDefinition; //var dotnetRef = dotnetType.GetElementType(); var propertyList = new List <ObjectEvent>(); foreach (var ei in dotnetType.Events) { if (ei.Name.StartsWith("<")) { continue; } var eiRef = ei.EventType; if (NoInheritedMembers && eiRef.DeclaringType != dotnetType) { continue; } var eventObject = new ObjectEvent(); eventObject.Name = ei.Name; eventObject.Type = ei.EventType.Name; eventObject.Scope = "public"; eventObject.Signature = FixupMemberNameForSignature(ei.FullName); eventObject.DeclaringType = ei.DeclaringType.FullName; eventObject.Syntax = $"{eventObject.Scope} {eventObject.Other} {eventObject.Type} {eventObject.Name}"; eventObject.Syntax = eventObject.Syntax.Replace(" ", " "); propertyList.Add(eventObject); } dotnetObject.Events.AddRange(propertyList); }
/// <summary> /// This method parses comments from C# XML documentation into the appropriate /// cHelpText properties. /// </summary> /// <returns></returns> public bool ParseXmlProperties(DotnetObject dotnetObject) { string xPath; XmlDocument oDom = new XmlDocument(); try { oDom.Load("file://" + XmlDocFile); } catch (Exception ex) { ErrorMessage = "Unable to load XML Documentation file." + ex.Message; return(false); } XmlNode Match = null; XmlNode SubMatch = null; try { Match = oDom.SelectSingleNode("/doc/members/member[@name='" + "T:" + dotnetObject.Signature + "']"); dotnetObject.HelpText = GetNodeValue(Match, "summary") ?? string.Empty; dotnetObject.Remarks = GetNodeValue(Match, "remarks"); dotnetObject.Example = GetExampleCode(Match); var dotnetObjectRemarks = dotnetObject.Remarks.Trim(); var dotnetObjectHelpText = dotnetObject.HelpText.Trim(); dotnetObjectHelpText = dotnetObjectHelpText.Replace("\r", ""); dotnetObjectHelpText = dotnetObjectHelpText.Replace("\n\n", "#$#$#$"); dotnetObjectHelpText = dotnetObjectHelpText.Replace("\n", " "); dotnetObjectHelpText = dotnetObjectHelpText.Replace("#$#$#$", "\r\n\r\n"); dotnetObject.SeeAlso = FixupSeeAlsoLinks(ref dotnetObjectHelpText) + FixupSeeAlsoLinks(ref dotnetObjectRemarks); dotnetObject.HelpText = dotnetObjectHelpText; dotnetObject.Remarks = dotnetObjectRemarks; dotnetObject.Contract = GetContracts(Match); Match = null; } catch (Exception ex) { string lcError = ex.Message; } // *** Loop through the methods foreach (var method in dotnetObject.AllMethods) { // *** Strip off empty method parens string MethodSignature = method.Signature.Replace("()", ""); // *** Replace Reference of Reflection for the one use by XML docs MethodSignature = MethodSignature.Replace("&", "@"); if (method.RawParameters == "") { xPath = "/doc/members/member[@name='" + "M:" + MethodSignature + "']"; // .cNamespace + "." + loObject.cName + "." + loMethod.cName + "']"; } else { xPath = "/doc/members/member[@name='" + "M:" + MethodSignature + "']"; } // "M:" + loObject.cNamespace + "." + loObject.cName + "." + loMethod.cName + // "(" + loMethod.cRawParameters + ")']"; try { // M:Westwind.Utilities.Encryption.EncryptBytes(System.Byte[],System.String) Match = oDom.SelectSingleNode(xPath); if (Match == null) { continue; } method.HelpText = GetNodeValue(Match, "summary"); method.Remarks = GetNodeValue(Match, "remarks"); method.Example = GetExampleCode(Match); method.Contract = GetContracts(Match); var methodHelpText = method.HelpText; var methodRemarks = method.Remarks; method.SeeAlso = FixupSeeAlsoLinks(ref methodHelpText) + FixupSeeAlsoLinks(ref methodRemarks); method.HelpText = methodHelpText; method.Remarks = methodRemarks; //this.GetNodeValue(Match, "example"); // *** Only update returns if the return comment is actually set // *** Otherwise leave the type intact method.ReturnDescription = GetNodeValue(Match, "returns"); // *** Parse the parameters string parmDescriptions = ""; foreach (var parm in method.ParameterList) { parmDescriptions = parmDescriptions + "**" + parm + "** \r\n"; SubMatch = Match.SelectSingleNode("param[@name='" + parm + "']"); if (SubMatch != null) { string value = SubMatch.InnerText; if (value.Length > 0) { value = value.Trim(' ', '\t', '\r', '\n'); parmDescriptions = parmDescriptions + value + "\r\n\r\n"; } else { // empty line parmDescriptions = parmDescriptions + "\r\n"; } } } method.DescriptiveParameters = parmDescriptions; string Exceptions = ""; XmlNodeList ExceptionMatches = null; try { ExceptionMatches = Match.SelectNodes("exception"); } catch { } if (ExceptionMatches != null) { foreach (XmlNode Node in ExceptionMatches) { XmlAttribute Ref = Node.Attributes["cref"]; if (Ref != null) { Exceptions += "**" + Ref.Value.Replace("T:", "").Replace("!:", "") + "** \r\n"; } if (!string.IsNullOrEmpty(Node.InnerText)) { Exceptions += GetNodeValue(Node, "") + "\r\n"; } Exceptions += "\r\n"; } method.Exceptions = Exceptions.TrimEnd('\r', '\n'); } Match = null; } catch (Exception ex) { string lcError = ex.Message; } } // for methods // Combine properties and fields into a single list var propAndFieldList = new List <ObjectProperty>(); propAndFieldList.AddRange(dotnetObject.Properties); propAndFieldList.AddRange(dotnetObject.Fields); // *** Loop through the properties and fields in one pass so we can use the same logic foreach (var property in propAndFieldList) { string fieldPrefix = "P:"; if (property.PropertyMode == PropertyModes.Field) { fieldPrefix = "F:"; } xPath = "/doc/members/member[@name='" + fieldPrefix + property.Signature.Replace("()", "") + "']"; Match = oDom.SelectSingleNode(xPath); property.HelpText = GetNodeValue(Match, "summary"); property.Remarks = GetNodeValue(Match, "remarks"); property.Example = GetExampleCode(Match); property.Contract = GetContracts(Match); var propertyHelpText = property.HelpText; var propertyRemarks = property.Remarks; property.SeeAlso = FixupSeeAlsoLinks(ref propertyHelpText) + FixupSeeAlsoLinks(ref propertyRemarks); property.HelpText = propertyHelpText; property.Remarks = propertyRemarks; string value = GetNodeValue(Match, "value"); if (!string.IsNullOrEmpty(value)) { property.DefaultValue = value; } Match = null; } // for properties // *** Loop through the fields foreach (var evt in dotnetObject.Events) { string lcFieldPrefix = "E:"; xPath = "/doc/members/member[@name='" + lcFieldPrefix + evt.Signature + "']"; Match = oDom.SelectSingleNode(xPath); evt.HelpText = GetNodeValue(Match, "summary"); evt.Remarks = GetNodeValue(Match, "remarks"); evt.Example = GetExampleCode(Match); var evtHelpText = evt.HelpText; var evtRemarks = evt.Remarks; evt.SeeAlso = this.FixupSeeAlsoLinks(ref evtHelpText) + this.FixupSeeAlsoLinks(ref evtRemarks); evt.HelpText = evtHelpText; evt.Remarks = evtRemarks; Match = null; } // for events return(true); } // ParseXMLProperties (method)
/// <summary> /// This method parses comments from C# XML documentation into the appropriate /// cHelpText properties. /// </summary> /// <returns></returns> public bool ParseXmlProperties(DotnetObject PassedObject) { string xPath; DotnetObject Object; XmlDocument oDom = new XmlDocument(); try { oDom.Load("file://" + cXmlFilename); } catch (Exception ex) { cErrorMsg = "Unable to load XML Documentation file." + ex.Message; return(false); } // *** Get object descriptions for (int Objs = 0; Objs < nObjectCount; Objs++) { XmlNode Match = null; XmlNode SubMatch = null; if (PassedObject == null) { Object = aObjects[Objs]; } else { Object = PassedObject; Objs = nObjectCount - 1; } if (PassedObject != null && PassedObject.Name.ToLower() != Object.Name.ToLower()) { continue; } try { Match = oDom.SelectSingleNode("/doc/members/member[@name='" + "T:" + Object.RawSignature + "']"); Object.HelpText = GetNodeValue(Match, "summary"); Object.Remarks = GetNodeValue(Match, "remarks"); Object.Example = GetExampleCode(Match); Object.SeeAlso = FixupSeeAlsoLinks(ref Object.HelpText) + FixupSeeAlsoLinks(ref Object.Remarks); Object.Contract = GetContracts(Match); Match = null; } catch (Exception ex) { string lcError = ex.Message; } // *** Loop through the methods for (int lnMethods = 0; lnMethods < Object.MethodCount; lnMethods++) { ObjectMethod method = Object.Methods[lnMethods]; // *** Strip off empty method parens string methodSignature = method.Signature.Replace("()", ""); // *** Replace Reference of Reflection for the one use by XML docs methodSignature = methodSignature.Replace("&", "@"); if (method.RawParameters == "") { xPath = "/doc/members/member[@name='" + "M:" + methodSignature + "']"; // .cNamespace + "." + loObject.cName + "." + loMethod.cName + "']"; } else { xPath = "/doc/members/member[@name='" + "M:" + methodSignature + "']"; } // "M:" + loObject.cNamespace + "." + loObject.cName + "." + loMethod.cName + // "(" + loMethod.cRawParameters + ")']"; try { Match = oDom.SelectSingleNode(xPath); if (Match == null) { continue; } method.HelpText = GetNodeValue(Match, "summary"); method.Remarks = GetNodeValue(Match, "remarks"); method.Example = GetExampleCode(Match); method.Contract = GetContracts(Match); method.SeeAlso = FixupSeeAlsoLinks(ref method.HelpText) + FixupSeeAlsoLinks(ref method.Remarks); //this.GetNodeValue(Match, "example"); // *** Only update returns if the return comment is actually set // *** Otherwise leave the type intact method.ReturnDescription = GetNodeValue(Match, "returns"); // *** Parse the parameters string lcParmDescriptions = ""; for (int x = 0; x < method.ParameterCount; x++) { string parm = method.ParameterList[x].Trim(); lcParmDescriptions = lcParmDescriptions + "**" + parm + "** \r\n"; SubMatch = Match.SelectSingleNode("param[@name='" + parm + "']"); if (SubMatch != null) { string lcValue = SubMatch.InnerText; if (lcValue.Length > 0) { lcValue = lcValue.Trim(' ', '\t', '\r', '\n'); lcParmDescriptions = lcParmDescriptions + lcValue + "\r\n\r\n"; } else { // empty line lcParmDescriptions = lcParmDescriptions + "\r\n"; } } } method.DescriptiveParameters = lcParmDescriptions; string Exceptions = ""; XmlNodeList ExceptionMatches = null; try { ExceptionMatches = Match.SelectNodes("exception"); } catch {; } if (ExceptionMatches != null) { foreach (XmlNode Node in ExceptionMatches) { XmlAttribute Ref = Node.Attributes["cref"]; if (Ref != null) { Exceptions += "**" + Ref.Value.Replace("T:", "").Replace("!:", "") + "** \r\n"; } if (!string.IsNullOrEmpty(Node.InnerText)) { Exceptions += GetNodeValue(Node, "") + "\r\n"; } Exceptions += "\r\n"; } method.Exceptions = Exceptions.TrimEnd('\r', '\n'); } Match = null; } catch (Exception ex) { string lcError = ex.Message; } } // for methods // *** Loop through the properties for (int lnFields = 0; lnFields < Object.PropertyCount; lnFields++) { ObjectProperty property = Object.Properties[lnFields]; string fieldPrefix = "F:"; if (property.FieldOrProperty != "Field") { fieldPrefix = "P:"; } xPath = "/doc/members/member[@name='" + fieldPrefix + property.Signature + "']"; Match = oDom.SelectSingleNode(xPath); property.HelpText = GetNodeValue(Match, "summary"); property.Remarks = GetNodeValue(Match, "remarks"); property.Example = GetExampleCode(Match); property.Contract = GetContracts(Match); property.SeeAlso = FixupSeeAlsoLinks(ref property.HelpText) + FixupSeeAlsoLinks(ref property.Remarks); string value = GetNodeValue(Match, "value"); if (!string.IsNullOrEmpty(value)) { property.DefaultValue = value; } Match = null; } // for properties // *** Loop through the fields for (int lnFields = 0; lnFields < Object.EventCount; lnFields++) { ObjectEvent loEvent = Object.Events[lnFields]; string lcFieldPrefix = "E:"; xPath = "/doc/members/member[@name='" + lcFieldPrefix + loEvent.Signature + "']"; Match = oDom.SelectSingleNode(xPath); loEvent.HelpText = GetNodeValue(Match, "summary"); loEvent.Remarks = GetNodeValue(Match, "remarks"); loEvent.Example = GetExampleCode(Match); loEvent.SeeAlso = FixupSeeAlsoLinks(ref loEvent.HelpText) + FixupSeeAlsoLinks(ref loEvent.Remarks); Match = null; } // for events } // for objects return(true); } // ParseXMLProperties (method)
/// <summary> /// Internal method that's used to parse the currently selected object /// parsing methods and properties and the various object properties including /// object inheritance etc. /// </summary> /// <param name="dotnetObject"></param> /// <param name="type"></param> /// <param name="dontParseMethods"></param> protected void ParseObject(DotnetObject dotnetObject, Type type, bool dontParseMethods) { // *** Pass down high level options dotnetObject.Name = type.Name; dotnetObject.RawTypeName = type.Name; dotnetObject.Syntax = cSyntax; dotnetObject.RetrieveDeclaredMembersOnly = RetrieveDeclaredMembersOnly; bool IsVb = cSyntax.StartsWith("VB"); // *** If we have a generic type strip off if (type.IsGenericType) { dotnetObject.Name = DotnetObject.GetGenericTypeName(type, GenericTypeNameFormats.TypeName); } dotnetObject.FormattedName = dotnetObject.TypeNameForLanguage(dotnetObject.Name); // *** Parse basic type features if (type.IsPublic || type.IsNestedPublic) { dotnetObject.Scope = "public"; } if (!type.IsVisible) { dotnetObject.Scope = "internal"; dotnetObject.Internal = true; } else if (type.IsNotPublic || type.IsNestedPrivate) { dotnetObject.Scope = "private"; } if (IsVb) { dotnetObject.Scope = StringUtils.ProperCase(dotnetObject.Scope); } if (type.IsSealed && type.IsAbstract) { dotnetObject.Other = "static"; } else { if (type.IsSealed) { if (IsVb) { dotnetObject.Other = "NotInheritable"; } else { dotnetObject.Other = "sealed"; } } if (type.IsAbstract) { if (IsVb) { dotnetObject.Other = "MustInherit"; } else { dotnetObject.Other += "abstract"; } } } // *** Get the type 'signature' dotnetObject.Signature = type.FullName; dotnetObject.RawSignature = dotnetObject.Signature; //// *** Generic Type: Replace signature wwBusiness`1 with wwBusiness<EntityType> (cName) //if (loType.IsGenericType) // loObject.cSignature = loObject.cSignature.Substring(0, loObject.cSignature.LastIndexOf(".")+1) + loObject.cName; dotnetObject.Namespace = type.Namespace; dotnetObject.Assembly = type.Assembly.CodeBase; dotnetObject.Assembly = dotnetObject.Assembly.Substring(dotnetObject.Assembly.LastIndexOf("/") + 1); dotnetObject.Type = "class"; if (type.IsInterface) { dotnetObject.Type = "interface"; } else if (type.IsEnum) { dotnetObject.Type = "enum"; } else if (type.IsValueType) { dotnetObject.Type = "struct"; } // *** Figure out the base type and build inheritance tree // *** for this class if (type.BaseType != null) { string BaseTypeName = null; if (type.BaseType.IsGenericType) { //BaseTypeName = DotnetObject.GetGenericTypeName(type.BaseType, GenericTypeNameFormats.TypeName); //else BaseTypeName = type.BaseType.Name; } dotnetObject.InheritsFrom = dotnetObject.TypeNameForLanguage(BaseTypeName); if (dotnetObject.InheritsFrom == "MulticastDelegate" || dotnetObject.InheritsFrom == "Delegate") { dotnetObject.Type = "delegate"; } Type[] Implementations = type.GetInterfaces(); if (Implementations != null) { foreach (Type Implementation in Implementations) { // *** This will work AS LONG AS THE INTERFACE HAS AT LEAST ONE MEMBER! // *** This will give not show an 'empty' placeholder interface // *** Can't figure out a better way to do this... InterfaceMapping im = type.GetInterfaceMap(Implementation); if (im.TargetMethods.Length > 0 && im.TargetMethods[0].DeclaringType == type) { if (Implementation.IsGenericType) { dotnetObject.Implements += DotnetObject.GetGenericTypeName(Implementation, GenericTypeNameFormats.TypeName) + ","; } else { dotnetObject.Implements += Implementation.Name + ","; } } } if (dotnetObject.Implements != "") { dotnetObject.Implements = dotnetObject.Implements.TrimEnd(','); } } // *** Create the Inheritance Tree List <string> Tree = new List <string>(); Type Current = type; while (Current != null) { if (Current.IsGenericType) { Tree.Add(dotnetObject.TypeNameForLanguage(DotnetObject.GetGenericTypeName(Current, GenericTypeNameFormats.FullTypeName))); } else { Tree.Add(Current.FullName); } Current = Current.BaseType; } // *** Walk our list backwards to build the string for (int z = Tree.Count - 1; z >= 0; z--) { dotnetObject.InheritanceTree += Tree[z] + "\r\n"; } } if (!dontParseMethods) { //dotnetObject.LoadMethods(type); //dotnetObject.LoadProperties(type); //dotnetObject.LoadEvents(type); } }
/// <summary> /// Parses an object by name and sets the oObject /// member with the result. /// </summary> /// <param name="className">Class name to search</param> /// <returns></returns> public bool GetObject(string className) { lError = false; bool GenericType = (className.IndexOf("<") > -1); string BaseType = className; if (GenericType) { BaseType = className.Substring(0, className.IndexOf("<")); } if (aObjects == null) { if (GetAllObjects(true) == 0 && lError) { return(false); } } for (int x = 0; x < aXObjects.Length; x++) { Type loType = aXObjects[x]; // Check for Obsolete members IList <CustomAttributeData> attrs = CustomAttributeData.GetCustomAttributes(loType); bool isObsolete = false; foreach (CustomAttributeData attr in attrs) { string name = attr.ToString(); if (name.Contains("ObsoleteAttribute(")) { isObsolete = true; break; } } // skip over this type if (isObsolete) { continue; } // *** Check for matching type or generic type if (!(loType.Name.ToLower() == className.ToLower() || (GenericType && loType.Name.ToLower().StartsWith(BaseType.ToLower() + "`"))) ) { continue; } oObject = new DotnetObject(); oObject.Name = loType.Name; oObject.RawTypeName = loType.Name; oObject.Syntax = cSyntax; oObject.RetrieveDeclaredMembersOnly = RetrieveDeclaredMembersOnly; ParseObject(oObject, loType, false); } if (cXmlFilename.Length > 0) { ParseXmlProperties(oObject); } return(true); }
/// <summary> /// Gets all objects into the aObjects array and parses all method/properties into the subarrays. /// </summary> /// <param name="DontParseMethods">if true methods and properties are not parsed</param> /// <returns></returns> public int GetAllObjects(bool DontParseMethods) { lError = false; Assembly assembly; try { // Load up full assembly AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; assembly = Assembly.LoadFrom(Filename); // Load up reflection only assembly - fails with runtime version fixups //AppDomain.CurrentDomain.ReflectionOnlyAssemblyResolve += CurrentDomain_ReflectionOnlyAssemblyResolve; //assembly = System.Reflection.Assembly.ReflectionOnlyLoadFrom(this.cFilename); } catch (Exception ex) { lError = true; cErrorMsg = String.Format("Unable to load assembly.\r\n" + "Typically this is caused by missing dependent assemblies\r\n" + "or an assembly compiled using a runtime higher than this version: {0}.\r\n\r\n" + "Raw Error:\r\n{1}", Environment.Version.ToString(), ex.GetBaseException().Message); return(0); } try { aXObjects = assembly.GetTypes(); } catch (Exception ex) { lError = true; cErrorMsg = String.Format("Unable to load types from assembly.\r\n" + "Typically this is caused by missing dependent assemblies\r\n" + "or an assembly compiled using a runtime higher than this version: {0}.\r\n\r\n" + "Raw Error:\r\n{1}", Environment.Version.ToString(), ex.GetBaseException().Message); return(0); } try { int Count = aXObjects.Length; if (Count == 0) { return(0); } nObjectCount = Count; aObjects = new DotnetObject[Count]; for (int x = 0; x < aXObjects.Length; x++) { Type type = aXObjects[x]; aObjects[x] = new DotnetObject(); ParseObject(aObjects[x], type, DontParseMethods); } if (!DontParseMethods && cXmlFilename.Length > 0) { ParseXmlProperties(null); } ArrayList al = new ArrayList(aObjects); al.Sort(); aObjects = al.ToArray(typeof(DotnetObject)) as DotnetObject[]; return(Count); } catch (Exception ex) { lError = true; cErrorMsg = ex.Message + "\r\n\r\n" + ex.StackTrace + "\r\n"; return(0); } }
/// <summary> /// Parses all fields for the type passed /// </summary> /// <param name="dotnetObject"></param> public void ParseFields(DotnetObject dotnetObject) { var dotnetType = dotnetObject.TypeDefinition; //var dotnetRef = dotnetType.GetElementType(); var propertyList = new List <ObjectProperty>(); foreach (var pi in dotnetType.Fields) { if (pi.Name.StartsWith("<")) { continue; } var piRef = pi.FieldType; if (NoInheritedMembers && piRef.DeclaringType != dotnetType) { continue; } var prop = new ObjectProperty(); prop.Name = FixupStringTypeName(pi.FieldType.Name); prop.PropertyMode = PropertyModes.Field; if (pi.IsStatic) { prop.Static = pi.IsStatic; prop.Other += "static "; } if (!string.IsNullOrEmpty(prop.Other)) { prop.Other = prop.Other.Trim(); } // *** Parse basic type features if (pi.IsPublic) { prop.Scope = "public"; } // TODO: Internal Protected needs to be addressed else if (pi.IsAssembly || pi.IsFamilyOrAssembly) { prop.Scope = "internal"; prop.Internal = true; } else if (pi.IsPrivate) { prop.Scope = "private"; } if (!piRef.IsGenericInstance) { prop.Type = FixupStringTypeName(pi.Name); } else { prop.Type = DotnetObject.GetGenericTypeName(pi.FieldType, GenericTypeNameFormats.TypeName); } prop.Syntax = $"{prop.Scope} {prop.Other} {prop.Type} {prop.Name}" + prop.Name; prop.Syntax = prop.Syntax.Replace(" ", " "); prop.Signature = prop.Signature = FixupMemberNameForSignature(pi.FullName); prop.DeclaringType = pi.DeclaringType.FullName; propertyList.Add(prop); } dotnetObject.Properties.AddRange(propertyList); }
/// <summary> /// Parses all properties for the type passed /// </summary> /// <param name="dotnetObject"></param> public void ParseProperties(DotnetObject dotnetObject) { var dotnetType = dotnetObject.TypeDefinition; //var dotnetRef = dotnetType.GetElementType(); var propertyList = new List <ObjectProperty>(); foreach (var pi in dotnetType.Properties) { var piRef = pi.PropertyType; //if (NoInheritedMembers && piRef.DeclaringType != dotnetType) // continue; var prop = new ObjectProperty(); prop.Name = pi.Name; if (prop.Name.StartsWith("<")) { continue; } prop.Classname = pi.DeclaringType.Name; prop.PropertyMode = PropertyModes.Property; MethodDefinition mi; if (pi.GetMethod != null) { mi = pi.GetMethod; } else { mi = pi.SetMethod; } if (mi.IsPrivate) { return; } if (mi.IsAbstract) { prop.Other += "abstract "; } if (mi.IsVirtual && !mi.IsAbstract) { prop.Other += "virtual "; } if (mi.IsStatic) { prop.Static = mi.IsStatic; prop.Other += "static "; } if (mi.IsFinal) { prop.Other += "sealed "; } if (pi.SetMethod != null && pi.GetMethod != null) { } else if (pi.SetMethod == null) { prop.Other += "readonly "; } else if (pi.GetMethod == null) { prop.Other += "writeonly "; } if (!string.IsNullOrEmpty(prop.Other)) { prop.Other = prop.Other.Trim(); } // *** Parse basic type features if (mi.IsPublic) { prop.Scope = "public"; } // TODO: Internal Protected needs to be addressed else if (mi.IsAssembly || mi.IsFamilyOrAssembly) { prop.Scope = "internal"; prop.Internal = true; } else if (mi.IsPrivate) { prop.Scope = "private"; } if (!piRef.IsGenericInstance) { prop.Type = FixupStringTypeName(pi.PropertyType.Name); } else { prop.Type = DotnetObject.GetGenericTypeName(pi.PropertyType, GenericTypeNameFormats.TypeName); } prop.Syntax = $"{prop.Scope} {prop.Other} {prop.Type} {prop.Name}"; prop.Syntax = prop.Syntax.Replace(" ", " "); prop.Signature = FixupMemberNameForSignature(pi.FullName); prop.DeclaringType = pi.DeclaringType.FullName; propertyList.Add(prop); } dotnetObject.Properties.AddRange(propertyList); }
private void ParseMethodsOnType(DotnetObject dotnetObject, Collection <MethodDefinition> methods, TypeDefinition dotnetType) { var methodList = new List <ObjectMethod>(); foreach (var mi in methods) { var meth = new ObjectMethod(); var miRef = mi.GetElementMethod(); if (NoInheritedMembers && miRef.DeclaringType != dotnetType) { continue; } meth.Name = mi.Name; if (meth.Name.StartsWith("<") || mi.IsGetter || mi.IsSetter || mi.IsAddOn || mi.IsRemoveOn || mi.IsPrivate) { continue; } meth.Classname = mi.DeclaringType.Name; if (mi.IsConstructor) { // no static or base class constructors if (mi.IsStatic || mi.DeclaringType.FullName != dotnetObject.TypeDefinition.FullName) { continue; // don't document static constructors } meth.IsConstructor = true; meth.Name = dotnetObject.Name; } if (mi.IsPublic) { meth.Scope = "public"; } // TODO: Internal Protected needs to be addressed else if (mi.IsAssembly || mi.IsFamilyOrAssembly) { meth.Scope = "internal"; meth.Internal = true; } else if (mi.IsPrivate) { meth.Scope = "private"; } if (mi.IsAbstract) { meth.Other += "abstract "; } if (mi.IsVirtual && !mi.IsAbstract) { meth.Other += "virtual "; } if (mi.IsStatic) { meth.Static = mi.IsStatic; meth.Other += "static "; } if (mi.IsFinal) { meth.Other += "sealed "; } if (mi.HasGenericParameters || mi.ContainsGenericParameter) { meth.GenericParameters = "<"; var genericParms = miRef.GenericParameters; foreach (var genericArg in genericParms) { meth.GenericParameters += genericArg.Name + ","; } meth.GenericParameters = meth.GenericParameters.TrimEnd(','); meth.GenericParameters += ">"; if (meth.GenericParameters == "<>") { meth.GenericParameters = ""; } } foreach (var parm in mi.Parameters) { var methodParm = new MethodParameter(); methodParm.Name = parm.Name; if (methodParm.Name.EndsWith("&")) { methodParm.Other = "ref "; methodParm.Name = methodParm.Name.TrimEnd('&'); } methodParm.ShortTypeName = FixupStringTypeName(parm.ParameterType.Name); if (parm.ParameterType.IsGenericInstance) { methodParm.ShortTypeName = DotnetObject.GetGenericTypeName(parm.ParameterType.GetElementType(), GenericTypeNameFormats.TypeName); } methodParm.Type = parm.ParameterType.FullName; meth.ParameterList.Add(methodParm); } meth.ReturnType = mi.ReturnType.FullName; var simpleRetName = mi.ReturnType.Name; if (!mi.ReturnType.IsGenericParameter) { simpleRetName = FixupStringTypeName(simpleRetName); } var sbSyntax = new StringBuilder(); sbSyntax.Append($"{dotnetObject.Scope} {dotnetObject.Other} {simpleRetName} {meth.Name}{meth.GenericParameters}("); var parmCounter = 0; foreach (var parm in meth.ParameterList) { sbSyntax.Append($"{parm.ShortTypeName} {parm.Name}, "); parmCounter++; if (parmCounter % 2 == 0) { sbSyntax.Append("\r\n\t\t\t"); } } meth.Syntax = sbSyntax.ToString(); meth.Syntax = meth.Syntax.TrimEnd(' ', ',', '\r', '\n', '\t') + ")"; meth.Syntax = meth.Syntax.Replace(" ", " ").Replace(" ", " "); if (meth.IsConstructor) { meth.Signature = mi.DeclaringType.FullName + ".#ctor"; } string parameters = ""; string rawParameters = ""; meth.Signature = mi.FullName; // strip off return type var idx = meth.Signature.IndexOf(' '); if (idx > -1) { meth.Signature = meth.Signature.Substring(idx).TrimStart(); } // fix up ctor meth.Signature = meth.Signature.Replace("::.ctor", ".#ctor"); // fix up object member syntax and double conversions meth.Signature = meth.Signature .Replace("::", ".") .Replace("..", ".") .Trim(); // fix up parameters if (meth.Signature.EndsWith("()")) { // no parms has no parens ie. .method meth.Signature = meth.Signature.Substring(0, meth.Signature.Length - 2); } else { // fix up parameters for generics // from: .method(System.Collections.Generic.IDictionary`2(System.String,System.Object),System.String) // to: .method(System.Collections.Generic.IDictionary{System.String,System.Object},System.String) var origParms = StringUtils.ExtractString(meth.Signature, "(", ")", returnDelimiters: true); var newParms = origParms; if (origParms.Contains("`")) { var regEx = new Regex("`.*?<(.*?)>"); var matches = regEx.Matches(meth.Signature); foreach (Match match in matches) { var orig = match.Value; var type = match.Groups[1].Value; newParms = newParms.Replace(orig, "{" + type + "}"); } } if (!newParms.Equals(origParms)) { meth.Signature = meth.Signature.Replace(origParms, newParms); } } methodList.Add(meth); } dotnetObject.AllMethods.AddRange(methodList .OrderBy(ml => !ml.IsConstructor) .ThenBy(ml => ml.Name.ToLowerInvariant())); }
/// <summary> /// Parses an object based on a Mono.Cecil type definition /// </summary> /// <param name="type"></param> /// <param name="dontParseMembers"></param> /// <returns></returns> public DotnetObject ParseObject(TypeDefinition type, bool dontParseMembers = false) { if (type.Name.StartsWith("<")) { return(null); } var dotnetObject = new DotnetObject { Name = type.Name, RawTypeName = type.Name, Assembly = type.Module.Assembly.Name.Name, TypeDefinition = type }; // *** If we have a generic type strip off if (type.HasGenericParameters) { dotnetObject.Name = DotnetObject.GetGenericTypeName(type, GenericTypeNameFormats.TypeName); } dotnetObject.FormattedName = FixupStringTypeName(dotnetObject.Name); // *** Parse basic type features if (type.IsPublic || type.IsNestedPublic) { dotnetObject.Scope = "public"; } else if (type.IsNestedFamilyOrAssembly || type.IsNestedFamily) { dotnetObject.Scope = "internal"; dotnetObject.Internal = true; } else if (type.IsNotPublic || type.IsNestedPrivate) { dotnetObject.Scope = "private"; } if (type.IsSealed && type.IsAbstract) { dotnetObject.Other = "static"; } else { if (type.IsSealed && !type.IsEnum) { dotnetObject.Other = "sealed"; } if (type.IsAbstract && !type.IsInterface) { dotnetObject.Other += "abstract"; } } dotnetObject.IsInterface = type.IsInterface; dotnetObject.IsAbstract = type.IsAbstract; dotnetObject.Namespace = type.Namespace; dotnetObject.Signature = type.FullName; dotnetObject.Type = "class"; if (type.IsInterface) { dotnetObject.Type = "interface"; } else if (type.IsEnum) { dotnetObject.Type = "enum"; } else if (type.IsValueType) { dotnetObject.Type = "struct"; } if (type.BaseType != null) { string baseTypeName = null; if (type.BaseType.HasGenericParameters || type.BaseType.IsGenericInstance) { baseTypeName = DotnetObject.GetGenericTypeName(type.BaseType, GenericTypeNameFormats.TypeName); } else { baseTypeName = type.BaseType.Name; } if (baseTypeName == "Object" || baseTypeName == "Enum" || baseTypeName == "Delegate") { dotnetObject.InheritsFrom = null; } else { dotnetObject.InheritsFrom = FixupStringTypeName(baseTypeName); } if (dotnetObject.InheritsFrom == "MulticastDelegate" || dotnetObject.InheritsFrom == "Delegate") { dotnetObject.Type = "delegate"; } var implentations = type.Interfaces; //.GetInterfaces(); if (implentations != null) { foreach (var implementation in implentations) { // *** This will work AS LONG AS THE INTERFACE HAS AT LEAST ONE MEMBER! // *** This will give not show an 'empty' placeholder interface // *** Can't figure out a better way to do this... //InterfaceMapping im = type.GetInterfaceMap(implementation); //if (im.TargetMethods.Length > 0 && im.TargetMethods[0].DeclaringType == type) //{ if (implementation.InterfaceType.IsGenericInstance) { dotnetObject.Implements += DotnetObject.GetGenericTypeName(implementation.InterfaceType, GenericTypeNameFormats.TypeName) + ","; } else { dotnetObject.Implements += implementation.InterfaceType.Name + ","; } //} } if (!string.IsNullOrEmpty(dotnetObject.Implements)) { dotnetObject.Implements = dotnetObject.Implements.TrimEnd(','); } } // *** Create the Inheritance Tree List <string> Tree = new List <string>(); var current = type; while (current != null) { if (current.IsGenericInstance) { Tree.Insert(0, FixupStringTypeName(DotnetObject.GetGenericTypeName(current, GenericTypeNameFormats.FullTypeName))); } else { Tree.Insert(0, current.FullName); } var tref = current.BaseType as TypeReference; if (tref == null) { break; } var tdef = new TypeDefinition(tref.Namespace, tref.Name, Mono.Cecil.TypeAttributes.Class, tref); if (current.FullName == tdef.FullName) { break; } current = tdef; } StringBuilder sb = new StringBuilder(); // *** Walk our list backwards to build the string foreach (var ti in Tree) { sb.AppendLine(ti + " "); } dotnetObject.InheritanceTree = sb.ToString(); } dotnetObject.Syntax = $"{dotnetObject.Scope} {dotnetObject.Other} {dotnetObject.Type} {dotnetObject.Name}" .Replace(" ", " ") .Replace(" ", " "); if (!string.IsNullOrEmpty(dotnetObject.InheritsFrom)) { dotnetObject.Syntax += " : " + dotnetObject.InheritsFrom; } dotnetObject.Assembly = type.Module.FileName; dotnetObject.Assembly = Path.GetFileName(dotnetObject.Assembly); if (!dontParseMembers) { ParseMethods(dotnetObject); ParseFields(dotnetObject); ParseProperties(dotnetObject); ParseEvents(dotnetObject); } if (ParseXmlDocumentation) { var docFile = Path.ChangeExtension(AssemblyFilename, "xml"); if (File.Exists(docFile)) { var parser = new XmlDocumentationParser(docFile); if (!parser.ParseXmlProperties(dotnetObject)) { SetError(parser.ErrorMessage); } } } return(dotnetObject); }