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