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